{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 实现一个通用的MLP\n",
    "1. 可以设置隐藏层数和各隐藏层的神经元个数\n",
    "1. 有三种激活函数可以选择\n",
    "1. 学习率可以设置\n",
    "1. 可以选择要解决问题类型 如： 回归问题和分类问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from tqdm.auto import tqdm\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MLP:\n",
    "    def __init__(self, input_size: int, hidden_layer_num: int, hidden_size: tuple, output_size: int, lr: float, activation: str, type: str):\n",
    "        self.input_size = input_size\n",
    "        self.hidden_layer_num = hidden_layer_num\n",
    "        self.hidden_size = hidden_size  # 输入各隐藏层的神经元个数为元组对应位置的值\n",
    "        if len(hidden_size) != hidden_layer_num:\n",
    "            print(f'隐藏层参数设置有误!')\n",
    "            self.hidden_layer_error = True\n",
    "        else:\n",
    "            self.hidden_layer_error = False\n",
    "        self.output_size = output_size\n",
    "        self.lr = lr\n",
    "        self.activation = activation\n",
    "        self.type = type\n",
    "        np.random.seed(0)\n",
    "        # 初始化权重 Xavier Normal 初始化方法\n",
    "        self.weights = {}\n",
    "        combined_tuple = (input_size,) + hidden_size + (output_size,)\n",
    "        for i in range(hidden_layer_num+1):\n",
    "            std = np.sqrt(2./(combined_tuple[i]+combined_tuple[i+1]))\n",
    "            self.weights['w'+str(i+1)] = np.random.normal(loc=0,\n",
    "                                                          scale=std, size=(combined_tuple[i], combined_tuple[i+1]))\n",
    "\n",
    "        # 初始化偏置\n",
    "        self.biases = {}\n",
    "        for i in range(hidden_layer_num+1):\n",
    "            std = np.sqrt(2./(combined_tuple[i]+combined_tuple[i+1]))\n",
    "            self.biases['b'+str(i+1)] = np.random.normal(loc=0,\n",
    "                                                         scale=std, size=(1, combined_tuple[i+1]))\n",
    "\n",
    "        # Adam优化器初始参数\n",
    "        self.beta1 = 0.9\n",
    "        self.beta2 = 0.999\n",
    "        self.epsilon = 1e-8\n",
    "        self.m = {key: np.zeros_like(val) for key, val in self.weights.items()}\n",
    "        self.v = {key: np.zeros_like(val) for key, val in self.weights.items()}\n",
    "        self.t = 0\n",
    "\n",
    "    def sigmoid(self, x):\n",
    "        return 1 / (1 + np.exp(-x))\n",
    "\n",
    "    def sigmoid_derivative(self, x):\n",
    "        return self.sigmoid(x) * (1 - self.sigmoid(x))\n",
    "    \n",
    "    # relu函数\n",
    "    def relu(self, x):\n",
    "        return np.maximum(0, x)\n",
    "\n",
    "    # relu函数的导数\n",
    "    def relu_derivative(self, x):\n",
    "        return np.where(x > 0, 1, 0)\n",
    "\n",
    "    def tanh(self, x):\n",
    "        return np.tanh(x)\n",
    "\n",
    "    def tanh_derivative(self, x):\n",
    "        return 1 - self.tanh(x)**2\n",
    "\n",
    "    # softmax函数\n",
    "    def softmax(self, x):\n",
    "        exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))\n",
    "        return exp_x / np.sum(exp_x, axis=1, keepdims=True)\n",
    "\n",
    "    def forward(self, x):\n",
    "        self.y = {}  # y值不用\n",
    "        self.z = {'z0': x}  # x的值已在此处保存\n",
    "        for i in range(1, self.hidden_layer_num+1):\n",
    "            self.y['y'+str(i)] = self.z['z'+str(i-1)\n",
    "                                        ] @ self.weights['w'+str(i)]+self.biases['b'+str(i)]\n",
    "            if self.activation == 'relu':\n",
    "                self.z['z'+str(i)] = self.relu(self.y['y'+str(i)])\n",
    "            elif self.activation == 'sigmoid':\n",
    "                self.z['z'+str(i)] = self.sigmoid(self.y['y'+str(i)])\n",
    "            elif self.activation == 'tanh':\n",
    "                self.z['z'+str(i)] = self.tanh(self.y['y'+str(i)])\n",
    "\n",
    "        logits = self.z['z'+str(self.hidden_layer_num)] @ self.weights['w'+str(\n",
    "            self.hidden_layer_num+1)] + self.biases['b'+str(self.hidden_layer_num+1)]\n",
    "\n",
    "        if self.type == \"regression\":\n",
    "            output = logits\n",
    "            return output\n",
    "        elif self.type == \"classification\":\n",
    "            output = self.softmax(logits)\n",
    "            return output\n",
    "\n",
    "    def backward(self, y_true, output):\n",
    "        m = output.shape[0]\n",
    "        n = self.hidden_layer_num\n",
    "        grad = {}\n",
    "        self.dw = {}\n",
    "        self.db = {}\n",
    "        # grad['grad0']=0\n",
    "        grad['grad'+str(n+2)] = output - y_true  # 损失函数对输出值的导数 dL/dy\n",
    "        for i in range(1, n+2)[::-1]:\n",
    "            self.dw['dw'+str(i)] = self.z['z'+str(i-1)\n",
    "                                          ].T @ grad['grad'+str(i+1)] / m\n",
    "            self.db['db'+str(i)] = np.sum(grad['grad'+str(i+1)],\n",
    "                                          axis=0, keepdims=True) / m\n",
    "            if self.activation == 'relu':\n",
    "                grad['grad'+str(i)] = grad['grad'+str(i+1)] @ self.weights['w' +\n",
    "                                                                       str(i)].T * self.relu_derivative(self.z['z'+str(i-1)])\n",
    "            elif self.activation == 'sigmoid':\n",
    "                grad['grad'+str(i)] = grad['grad'+str(i+1)] @ self.weights['w' +\n",
    "                                                                       str(i)].T * self.sigmoid_derivative(self.z['z'+str(i-1)])\n",
    "            elif self.activation == 'tanh':\n",
    "                grad['grad'+str(i)] = grad['grad'+str(i+1)] @ self.weights['w' +\n",
    "                                                                       str(i)].T * self.tanh_derivative(self.z['z'+str(i-1)])\n",
    "\n",
    "        # 使用Adam优化器更新权重和偏差\n",
    "        self.t += 1\n",
    "        for key in self.weights.keys():\n",
    "\n",
    "            self.m[key] = self.beta1 * self.m[key] + \\\n",
    "                (1 - self.beta1) * self.dw['d' + key]\n",
    "\n",
    "            self.v[key] = self.beta2 * self.v[key] + \\\n",
    "                (1 - self.beta2) * self.dw['d' + key] ** 2\n",
    "\n",
    "            m_hat = self.m[key] / (1 - self.beta1 ** self.t)\n",
    "\n",
    "            v_hat = self.v[key] / (1 - self.beta2 ** self.t)\n",
    "\n",
    "            self.weights[key] -= self.lr * m_hat / \\\n",
    "                (np.sqrt(v_hat) + self.epsilon)\n",
    "            self.biases['b' + key[1:]] -= self.lr * self.db['db' + key[1:]]\n",
    "\n",
    "    def mean_squared_error_loss(self, y_pred, y_true):\n",
    "        \"\"\"\n",
    "        均方误差损失函数\n",
    "        :param y_pred : 预测值 \n",
    "        :param y_true : 真实值 \n",
    "        :returns loss : 损失值 \n",
    "        \"\"\"\n",
    "        loss = np.sum((y_pred-y_true)**2) / len(y_true)\n",
    "        return loss\n",
    "\n",
    "    def cross_entropy_loss(self, y_pred, y_true):\n",
    "        \"\"\"\n",
    "        交叉熵损失函数\n",
    "        :param y_pred : 预测值 \n",
    "        :param y_true : 真实值 \n",
    "        :returns loss : 损失值 \n",
    "        \"\"\"\n",
    "        loss = -np.mean(y_true * np.log(y_pred + 1e-9))  # 1e-9用于稳定数值计算\n",
    "        return loss\n",
    "\n",
    "    def train(self, x, y, epochs, batch_size):\n",
    "        self.epochs = epochs\n",
    "        self.batch_size = batch_size\n",
    "        self.best_loss = 1e10\n",
    "        self.losses = []\n",
    "        if self.type == 'classification':\n",
    "            self.accuracies = []\n",
    "        for epoch in tqdm(range(epochs)):\n",
    "            mini_x_trains = [x[k:k+batch_size]\n",
    "                             for k in range(0, x.shape[0], batch_size)]\n",
    "            mini_y_labels = [y[k:k+batch_size]\n",
    "                             for k in range(0, x.shape[0], batch_size)]\n",
    "\n",
    "            for mini_x_train, mini_y_label in zip(mini_x_trains, mini_y_labels):\n",
    "\n",
    "                output = self.forward(mini_x_train)\n",
    "\n",
    "                self.backward(mini_y_label, output)\n",
    "            if self.type == 'regression':\n",
    "                output = self.forward(x)\n",
    "                loss = self.mean_squared_error_loss(output, y)\n",
    "                # 记录所有损失值\n",
    "                self.losses.append(loss)\n",
    "                if loss < self.best_loss:  # 记录最好的一次损失下的参数值\n",
    "                    self.best_loss = loss\n",
    "                    under_best_loss_weights = self.weights\n",
    "                    under_best_loss_biases = self.biases\n",
    "                if (epoch+1) % 100 == 0:  # 每100轮输出损失值\n",
    "                    print(f'第{epoch+1}轮, loss = {loss}')\n",
    "            elif self.type == 'classification':\n",
    "                output = self.forward(x)\n",
    "                loss = self.cross_entropy_loss(output, y)\n",
    "                accuracy = np.mean(np.argmax(output, axis=1)\n",
    "                                   == np.argmax(y, axis=1))\n",
    "                # 记录所有损失值与准确值\n",
    "                self.losses.append(loss)\n",
    "                self.accuracies.append(accuracy)\n",
    "                if loss < self.best_loss:  # 记录最好的一次损失下的参数值\n",
    "                    self.best_loss = loss\n",
    "                    under_best_loss_weights = self.weights\n",
    "                    under_best_loss_biases = self.biases\n",
    "                print(\n",
    "                    f'第{epoch+1}轮, loss = {loss:.4f}, accuracy = {accuracy*100:.2f}%')\n",
    "\n",
    "        self.weights = under_best_loss_weights\n",
    "        self.biases = under_best_loss_biases\n",
    "\n",
    "    def data_load(self, file_path: str, is_train: bool, is_norm: bool, is_shuffle: bool, offset: float):\n",
    "        \"\"\"\n",
    "        数据加载\n",
    "        :param file_path : 文件路径\n",
    "        :param is_train : 是否为训练集\n",
    "        :param is_norm : 是否归一化\n",
    "        :param is_shuffle : 是否打乱数据\n",
    "        :param offset : 训练集和测试集比率\n",
    "        :returns : \n",
    "        \"\"\"\n",
    "        if self.type == 'regression':\n",
    "            # 读取CSV文件\n",
    "            df = pd.read_csv(file_path, na_values=[''])\n",
    "\n",
    "            # 将DataFrame转换为numpy数组\n",
    "            array = df.values\n",
    "            rows = array.shape[0]\n",
    "            columns = array.shape[1]\n",
    "            div_num_of_rows = round(rows * offset)\n",
    "            # 利用数组切片将原始数据划分\n",
    "            raw_train_data = array[0:div_num_of_rows, ...][...,\n",
    "                                                           0:self.input_size]\n",
    "            raw_train_labels = array[0:div_num_of_rows, ...][...,\n",
    "                                                             self.input_size:columns]\n",
    "            raw_test_data = array[div_num_of_rows:rows, ...][...,\n",
    "                                                             0:self.input_size]\n",
    "            raw_test_labels = array[div_num_of_rows:rows, ...][...,\n",
    "                                                               self.input_size:columns]\n",
    "            if is_train:\n",
    "                if is_norm:\n",
    "                    if is_shuffle:\n",
    "                        indices = np.arange(raw_train_data.shape[0])\n",
    "                        np.random.shuffle(indices)\n",
    "                        shuffled_train_data = raw_train_data[indices]\n",
    "                        shuffled_train_labels = raw_train_labels[indices]\n",
    "                        norm_train_data = self.normalization(\n",
    "                            shuffled_train_data)\n",
    "                        norm_train_labels = self.normalization(\n",
    "                            shuffled_train_labels)\n",
    "                        return norm_train_data, norm_train_labels\n",
    "                    else:\n",
    "                        norm_train_data = self.normalization(raw_train_data)\n",
    "                        norm_train_labels = self.normalization(\n",
    "                            raw_train_labels)\n",
    "                        return norm_train_data, norm_train_labels\n",
    "                else:\n",
    "                    if is_shuffle:\n",
    "                        indices = np.arange(raw_train_data.shape[0])\n",
    "                        np.random.shuffle(indices)\n",
    "                        shuffled_train_data = raw_train_data[indices]\n",
    "                        shuffled_train_labels = raw_train_labels[indices]\n",
    "                        return shuffled_train_data, shuffled_train_labels\n",
    "                    else:\n",
    "                        return raw_train_data, raw_train_labels\n",
    "            else:\n",
    "                if is_norm:\n",
    "                    if is_shuffle:\n",
    "                        indices = np.arange(raw_test_data.shape[0])\n",
    "                        np.random.shuffle(indices)\n",
    "                        shuffled_test_data = raw_test_data[indices]\n",
    "                        shuffled_test_labels = raw_test_labels[indices]\n",
    "                        norm_test_data = self.normalization(shuffled_test_data)\n",
    "                        norm_test_labels = self.normalization(\n",
    "                            shuffled_test_labels)\n",
    "                        return norm_test_data, norm_test_labels\n",
    "                    else:\n",
    "                        norm_test_data = self.normalization(raw_test_data)\n",
    "                        norm_test_labels = self.normalization(raw_test_labels)\n",
    "                        return norm_test_data, norm_test_labels\n",
    "                else:\n",
    "                    if is_shuffle:\n",
    "                        indices = np.arange(raw_test_data.shape[0])\n",
    "                        np.random.shuffle(indices)\n",
    "                        shuffled_test_data = raw_test_data[indices]\n",
    "                        shuffled_test_labels = raw_test_labels[indices]\n",
    "                        return shuffled_test_data, shuffled_test_labels\n",
    "                    else:\n",
    "                        return raw_test_data, raw_test_labels\n",
    "\n",
    "        elif self.type == 'classification':\n",
    "            pass\n",
    "\n",
    "    def normalization(self, data):\n",
    "        # 计算数据集的最大值，最小值，平均值\n",
    "        self.maximums, self.minimums, self.avgs = data.max(axis=0), data.min(axis=0), \\\n",
    "            data.sum(axis=0) / data.shape[0]\n",
    "        epsilon = 1e-8\n",
    "        # 对数据进行归一化处理\n",
    "        for i in range(data.shape[1]):\n",
    "            data[:, i] = (data[:, i] - self.avgs[i]) / \\\n",
    "                (self.maximums[i] - self.minimums[i] + epsilon)\n",
    "        return data\n",
    "\n",
    "    def inv_normalization(self, data):\n",
    "        \"\"\"\n",
    "        逆归一化\n",
    "        :param data : 逆归一化的数据  \n",
    "        :returns  : \n",
    "        \"\"\"\n",
    "        epsilon = 1e-8\n",
    "        for i in range(data.shape[1]):\n",
    "            data[:, i] = data[:, i] * \\\n",
    "                (self.maximums[i] - self.minimums[i] + epsilon) + self.avgs[i]\n",
    "        return data\n",
    "\n",
    "    def predict(self, x, y, isplot: bool,is_return_data:bool=None):\n",
    "        output = self.forward(x)\n",
    "        if self.type == 'regression':\n",
    "            output = self.inv_normalization(output)\n",
    "            y = self.inv_normalization(y)\n",
    "            loss = self.mean_squared_error_loss(output, y)\n",
    "            if isplot:\n",
    "                print(f'预测值 : {output.T}, 真实值 : {y.T}, loss = {loss}')\n",
    "                x = np.arange(1, len(y)+1)\n",
    "                # 绘制第一组数据，并设置颜色\n",
    "                plt.scatter(x, output, color='blue',\n",
    "                            label='predict')  # 第一组数据使用蓝色\n",
    "                # 绘制第二组数据，并设置不同的颜色\n",
    "                plt.scatter(x, y, color='red', label='true')  # 第二组数据使用红色\n",
    "                # 添加图例\n",
    "                plt.legend()\n",
    "                # 添加轴标签和图标题\n",
    "                plt.xlabel('X')\n",
    "                plt.ylabel('Y')\n",
    "                plt.title('predcit vs true')\n",
    "                plt.grid()\n",
    "                # 显示图表\n",
    "                plt.show()\n",
    "            else:\n",
    "                print(f'预测值 : {output.T}, 真实值 : {y.T}, loss = {loss}')\n",
    "        elif self.type == 'classification':\n",
    "            loss = self.cross_entropy_loss(output, y)\n",
    "            output = np.argmax(output, axis=1)  # 将预测值转换为数字\n",
    "            y = np.argmax(y.reshape(-1, self.output_size), axis=1)  # 将真实值转换为数字\n",
    "            accuracy = np.mean(output == y)\n",
    "            if isplot:\n",
    "                x = x.reshape(-1, 1).reshape(-1, 28, 28)  # 还原图片方便画图\n",
    "                for i, x in enumerate(x):\n",
    "                    plt.imshow(x, cmap='gray')  # cmap='gray'确保图像以灰度方式显示\n",
    "                    plt.axis('off')  # 关闭坐标轴显示\n",
    "                    plt.title('predict : '+str(output[i]))\n",
    "                    plt.show()  # 显示图像\n",
    "                print(\n",
    "                    f'预测值 : {output.T}, 真实值 : {y.T}, loss = {loss:.4f}, accuracy = {accuracy*100:.2f}%')\n",
    "            else:\n",
    "                print(\n",
    "                    f'预测值 : {output.T}, 真实值 : {y.T}, loss = {loss:.4f}, accuracy = {accuracy*100:.2f}%')\n",
    "                if is_return_data:\n",
    "                    return output,y\n",
    "    def __plot_loss__(self):\n",
    "        if self.type == 'regression':\n",
    "            x = np.arange(1, self.epochs+1)\n",
    "            plt.plot(x, self.losses)\n",
    "            plt.grid()\n",
    "            plt.title('loss')\n",
    "            plt.show()\n",
    "        elif self.type == 'classification':\n",
    "            x = np.arange(1, self.epochs+1)\n",
    "            plt.plot(x, self.losses)\n",
    "            plt.grid()\n",
    "            plt.title('loss')\n",
    "            plt.show()\n",
    "\n",
    "            plt.plot(x, self.accuracies)\n",
    "            plt.grid()\n",
    "            plt.title('accuracy')\n",
    "            plt.show()    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 波士顿房价预测问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2df0f5b1c4be407c9436f864402c9d6c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/500 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第100轮, loss = 0.0037101796554931217\n",
      "第200轮, loss = 0.0026587974791023577\n",
      "第300轮, loss = 0.0026364383822894146\n",
      "第400轮, loss = 0.0026545607213393652\n",
      "第500轮, loss = 0.0025465728747520854\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "预测值 : [[18.83844829  6.02905202 19.8980363  17.1895623  12.80367836 12.92885467\n",
      "  14.72634531 15.05529783 14.32284869 11.04663279 10.5997958  13.36870876\n",
      "  15.31339172 19.64798167 15.62649035 10.92207083  7.88390509 14.10898304\n",
      "  10.36353439 15.89003531 11.63462852  5.99147405 14.60123221 17.25747993\n",
      "  15.57819444  8.30437326 13.40632196 15.06504615 15.18921823 15.39608874\n",
      "  25.58191319 20.89527806 15.54612414 13.57548999 13.85416739  9.53638924\n",
      "  18.84161265 10.1365545   8.00248368 16.04508378 12.51450451 11.01476236\n",
      "  13.82959405 27.09451069 15.49378383 16.25529169 24.36999766 10.10787491\n",
      "  13.76155671 12.74671659 12.96511432 12.30605333 18.59915596  9.85913198\n",
      "  18.55454022 13.36850499 18.83902563 24.89972107 13.53032472  8.73894773\n",
      "  12.14236889 12.20115875 14.70229706 15.62456659 19.35878072 11.65180546\n",
      "  11.60465934  8.05060323 10.28575297 12.79164302 15.87976077 17.86941031\n",
      "  13.54852049 12.10058057 16.70370091 25.11721846 11.7794903  14.84017747\n",
      "  14.90967461 13.66110634 11.64331817 15.25514928 10.6712233  17.52178772\n",
      "  18.09975861 14.24386096 18.44811301 32.02818242 14.53059648  8.26434426\n",
      "  16.53341306 12.8109144   8.49815657 12.66594374  8.59826018  6.86934923\n",
      "  26.01029005 15.99909366 14.41681483 14.37789747]], 真实值 : [[21.8  7.  21.2 23.  11.7 14.9 14.1 20.6 19.7 10.8 11.8 14.2 14.9 17.2\n",
      "  20.2  7.5 10.4 19.5 10.5 13.4  9.6  5.  17.7 23.2 20.8  7.2 19.1  7.2\n",
      "  19.9 20.6 16.3 24.5 17.1 14.1 12.6  8.4 16.4 10.9 11.9 15.4 20.1  5.6\n",
      "   8.4 23.7 19.1 21.8 17.8 12.  21.4 13.5 20.  12.7 17.2  8.1 14.5 14.6\n",
      "  23.1 11.7 13.4  8.3 13.4 13.3 14.3 14.9 16.1 12.8  7.  17.9 15.  19.1\n",
      "  12.1 27.5 19.  15.2 17.5 10.2 11.  18.4 16.7 19.9 13.8 20.1  9.5 21.2\n",
      "  19.6 13.  15.2 25.  13.6  8.7 18.3 14.1  8.3 27.9  8.5  8.8 29.8 16.7\n",
      "  21.4 16.1]], loss = 21.19983880994584\n"
     ]
    }
   ],
   "source": [
    "model = MLP(input_size=13, hidden_layer_num=3, hidden_size=(6, 4, 2),\n",
    "            output_size=1, lr=0.001, activation='relu', type='regression')\n",
    "\n",
    "file_path = 'D:/python-learning-gitee/python-learning/机器学习/boston.csv'\n",
    "train_data, train_labels = model.data_load(\n",
    "    file_path=file_path, is_norm=True, is_train=True, is_shuffle=True, offset=0.8)\n",
    "\n",
    "model.train(train_data, train_labels, epochs=500, batch_size=2)\n",
    "\n",
    "model.__plot_loss__()\n",
    "\n",
    "test_data, test_labels = model.data_load(\n",
    "    file_path=file_path, is_norm=True, is_train=False, is_shuffle=True, offset=0.8)\n",
    "\n",
    "model.predict(test_data, test_labels, isplot=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数字识别问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torchvision.datasets import MNIST\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to MNIST\\raw\\train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 9912422/9912422 [00:30<00:00, 322248.74it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting MNIST\\raw\\train-images-idx3-ubyte.gz to MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to MNIST\\raw\\train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 28881/28881 [00:00<00:00, 108293.20it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting MNIST\\raw\\train-labels-idx1-ubyte.gz to MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to MNIST\\raw\\t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 1648877/1648877 [00:04<00:00, 410802.02it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting MNIST\\raw\\t10k-images-idx3-ubyte.gz to MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to MNIST\\raw\\t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 4542/4542 [00:00<00:00, 1057481.47it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting MNIST\\raw\\t10k-labels-idx1-ubyte.gz to MNIST\\raw\n",
      "\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c873461d79de4d54a644f2f74d3ae3a7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/10 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第1轮, loss = 0.0153, accuracy = 95.60%\n",
      "第2轮, loss = 0.0097, accuracy = 97.18%\n",
      "第3轮, loss = 0.0071, accuracy = 97.93%\n",
      "第4轮, loss = 0.0056, accuracy = 98.35%\n",
      "第5轮, loss = 0.0046, accuracy = 98.61%\n",
      "第6轮, loss = 0.0038, accuracy = 98.82%\n",
      "第7轮, loss = 0.0030, accuracy = 99.09%\n",
      "第8轮, loss = 0.0026, accuracy = 99.17%\n",
      "第9轮, loss = 0.0024, accuracy = 99.22%\n",
      "第10轮, loss = 0.0022, accuracy = 99.26%\n",
      "预测值 : [7 2 1 ... 4 5 6], 真实值 : [7 2 1 ... 4 5 6], loss = 0.0107, accuracy = 97.36%\n"
     ]
    }
   ],
   "source": [
    "model = MLP(input_size=784, hidden_layer_num=2, hidden_size=(128, 64),\n",
    "            output_size=10, lr=0.001, activation='relu', type='classification')\n",
    "\n",
    "# 加载MNIST数据集\n",
    "train_set = MNIST(\"\", train=True, download=True)\n",
    "test_set = MNIST(\"\", train=False, download=True)\n",
    "\n",
    "# 获取训练集和测试集的数据和标签\n",
    "train_images, train_labels = train_set.data, train_set.targets\n",
    "test_images, test_labels = test_set.data, test_set.targets\n",
    "\n",
    "# 将训练集和测试集的数据和标签转换为numpy类型\n",
    "train_images, train_labels = train_images.numpy(), train_labels.numpy()\n",
    "test_images, test_labels = test_set.data.numpy(), test_set.targets.numpy()\n",
    "\n",
    "# 将训练集的数据和标签一起打乱\n",
    "indices = np.arange(train_images.shape[0])\n",
    "np.random.shuffle(indices)\n",
    "train_images= train_images[indices]\n",
    "train_labels = train_labels[indices]\n",
    "\n",
    "# 训练集和测试集数据平铺并归一化\n",
    "train_images = train_images.reshape(-1, 784) / 255.0\n",
    "test_images = test_images.reshape(-1, 784) / 255.0\n",
    "\n",
    "# 训练集标签用one-hot编码\n",
    "train_labels = np.eye(10)[train_labels]\n",
    "test_labels = np.eye(10)[test_labels]\n",
    "\n",
    "\n",
    "model.train(train_images, train_labels, epochs=10, batch_size=128)\n",
    "predict_val,true_val=model.predict(test_images, test_labels, isplot=False,is_return_data=True)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 分类问题评估"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 混沌矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "confusion_matrix=np.zeros((10,10))\n",
    "\n",
    "counts={}\n",
    "for i in range(10):\n",
    "    for j in range(10):\n",
    "        counts[str(i)+str(j)]=0\n",
    "for predict_val,true_val in zip(predict_val,true_val):\n",
    "    counts[str(predict_val)+str(true_val)]+=1\n",
    "\n",
    "for key,val in counts.items():\n",
    "    confusion_matrix[int(key[0]),int(key[1])]=val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[9.690e+02, 1.000e+00, 4.000e+00, 0.000e+00, 4.000e+00, 2.000e+00,\n",
       "        4.000e+00, 1.000e+00, 5.000e+00, 2.000e+00],\n",
       "       [0.000e+00, 1.121e+03, 0.000e+00, 0.000e+00, 2.000e+00, 0.000e+00,\n",
       "        1.000e+00, 5.000e+00, 0.000e+00, 4.000e+00],\n",
       "       [1.000e+00, 4.000e+00, 1.007e+03, 4.000e+00, 4.000e+00, 0.000e+00,\n",
       "        1.000e+00, 1.600e+01, 4.000e+00, 0.000e+00],\n",
       "       [2.000e+00, 1.000e+00, 2.000e+00, 9.900e+02, 0.000e+00, 1.000e+01,\n",
       "        1.000e+00, 3.000e+00, 5.000e+00, 1.400e+01],\n",
       "       [1.000e+00, 0.000e+00, 5.000e+00, 0.000e+00, 9.450e+02, 1.000e+00,\n",
       "        4.000e+00, 0.000e+00, 4.000e+00, 9.000e+00],\n",
       "       [1.000e+00, 1.000e+00, 0.000e+00, 2.000e+00, 0.000e+00, 8.670e+02,\n",
       "        3.000e+00, 1.000e+00, 3.000e+00, 4.000e+00],\n",
       "       [1.000e+00, 3.000e+00, 6.000e+00, 2.000e+00, 7.000e+00, 6.000e+00,\n",
       "        9.440e+02, 0.000e+00, 5.000e+00, 2.000e+00],\n",
       "       [1.000e+00, 0.000e+00, 4.000e+00, 5.000e+00, 4.000e+00, 1.000e+00,\n",
       "        0.000e+00, 9.910e+02, 3.000e+00, 1.000e+01],\n",
       "       [3.000e+00, 4.000e+00, 4.000e+00, 3.000e+00, 1.000e+00, 5.000e+00,\n",
       "        0.000e+00, 5.000e+00, 9.450e+02, 7.000e+00],\n",
       "       [1.000e+00, 0.000e+00, 0.000e+00, 4.000e+00, 1.500e+01, 0.000e+00,\n",
       "        0.000e+00, 6.000e+00, 0.000e+00, 9.570e+02]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "confusion_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhAAAAGdCAYAAABDxkoSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB7KElEQVR4nO3deXxM1//H8VcyZCWRhSwUsSVksxP7Emqp2lWboqjSopZWNa2l1qD9drEvtdW+lbaKUpQu9trF0lJrFtllkcjM/P7wMzVJGMMk90o/T4/7eJh779x558y9yWfOuXeulV6v1yOEEEIIYQZrpQMIIYQQ4vkjBYQQQgghzCYFhBBCCCHMJgWEEEIIIcwmBYQQQgghzCYFhBBCCCHMJgWEEEIIIcwmBYQQQgghzCYFhBBCCCHMVkTpAA84dluqdIRHil/bV+kIQohCRu3fAWxlpXSCx7PL579e9jWGWGxbGcdnW2xbaqKaAkIIIYRQDSvpoDdFWkgIIYQQZpMeCCGEECIntY/hqIAUEEIIIUROMoRhkhQQQgghRE7SA2GSlFhCCCGEMJv0QAghhBA5yRCGSVJACCGEEDnJEIZJUmIJIYQQwmzSAyGEEELkJEMYJkkBIYQQQuQkQxgmPTclVjG7Isx4oy6R87oTt6oXu6e0p2ZFd6N1fEs7s350S24tDyN25evsn/YSZdwdDct9PIqzZlQL/ln8KlHfhPHNyGaUcrYrkPzHjh5h6DuDCG3WiGB/X/bs/rlAXvdpLF60kGB/X2ZETFE6ipG1q1fRtlUL6tQIJKxnd06fOqV0pDyprf0WL1rAaz26ElKnBs0ahzB86Dv8c+Wy0rHypLa2U/txO2/OLKoH+BpNnTq0UToW8Hztd+LpPDcFxJy3G9E82Js3Z+6n7ntb2H3yJlvHvYiXqwNwvzjYNbkdF28m0/aT7dR77zumbTxJZpYWAAfbInw/tjV6oP2EHYSO2YZNEWs2fBhaIIVmRkY6vr6+hI8Zn/8v9gzOnD7Fxg1rqVLFV+koRnZs38ZnMyIY+M5g1m7YjK+vH28P7E98fLzS0Yyosf2OHjnMK6+GsWLNehYsWkp2djaDBvQnPT1d6WhG1Nh2z8NxW7FSZX7+5TfDtPSb1UpHAp6f/e6RrKwtNxVSz8UQhp2Nhk71y9Fj+m5+j4wBYOr6E7Sr9QIDWvsxce2fjH+tJjv/vMGYlUcNz7sSc8fw/xC/UpQrWYwGo77nTsY9AN6a/Ss3l4XRLMCLvaej8vVnaNS4KY0aN83X13hW6WlphI8exfgJk1m0YJ7ScYysWL6ULt160KlzVwDGjJ/A/v2/sOXbTfQf8JbC6e5Ta/vNW7jY6PHEKdNo3jiEyHNnqVW7jkKpjKm17Z6H41aj0eDuXlLpGLk8D/vdY8kQhknPRWlUxNqKIhprMu9pjeZnZGkJqVoKKytoU/MFLkWl8N2Y1vyzuCe/RLzES3XKGta1KaJBD0bbuJulRafXE1LVo6B+FFWbOnkiTZo0pX5IA6WjGLmXlUXkubNGuaytralfvwGnTh5XMJkxtbZfTql37hfWTs7OCif51/PSdmp07dpVWjVvRPs2LQkf/R5RUbeUjpQnNe534tmY3QMRFxfHkiVLOHDgANHR0QB4enrSoEED3njjDUqWtHwlnHo3m4MXYhndLZjzN5KITb5Lj4Y+1KtSkr+j71DK2Z7i9kV5r1MgE9f+ydiVR2lVvTRrRrWg7Sfb+e1cDEcuxZJ2N5vJr9dm/OpjWFlZMTGsFkU01niWcLB45ufN9m0/Ehl5jtXrNiodJZfEpES0Wi1ubm5G893c3LiikjFVNbffw3Q6HTOmT6V6jZpUrlxF6TjA89N2ahQYFMTEyRGUL+9DXNxt5s+dQ7/eYWzc8gOOjsWUjmegxv3OpEI89GApZhUQR44c4cUXX8TBwYHQ0FCqVLm/I8TExDBz5kymTZvGTz/9RO3atR+7nczMTDIzM43m6bX3sNIUfeRz3py5n3nvNOLvRT3J1uo4cTmeDb9foXoFN0NP049HrjF76zkATv2TQD3fUrzZ2o/fzsUQl5JJr8/38uWAEN5uVw2dXs+G3y5z/O84dHq9Oc1Q6ERHRTFj2hQWLFqCra2t0nGeO89T+02dPIG/L11i2Qp1jJM/T22nRg8Pr1Tx9SMgMJh2rZuzc8d2OnftrmAyY2rb756IDGGYZFYBMXToULp37878+fOxytG4er2eQYMGMXToUA4cOPDY7URERDBhwgTjIFVfxqZap0c+50rMHdqM346DbRGc7IsSnZTB8hHN+CfmDvF3MrmXrSPyRrLRcy7cTCbEr5Th8e6Ttwgcsgm34rZka/Ukp2dxedEr/PPQuRL/RefOnSUhPp6e3bsY5mm1Wo4dPcLaNas4cvw0Go1GsXwuJVzQaDS5TpiMj4/H3d39Ec8qOGpvvwemTp7I/n2/sGT5Sjw8PZWOAzw/bfe8cHJyomy58ly/dk3pKAZq3O+eiPRAmGRWAXHy5EmWLVuWq3gAsLKyYsSIEdSoUcPkdsLDwxk5cqTRPM8+a58oQ3pmNumZ2ZRwtCG0ujdjVhzlXraOY3/HUcXbyWjdSl5OXL+dmmsb8Xfu9340DfCipLM9Px5Vz8GmhHr167Nxyw9G88Z/HE75ChXo23+A4r/Ai9rYULWaP4cOHqBFy1DgfpfooUMH6Pnq64pmA/W3n16vJ2LKJPbs3sXiZSsoU+YFRfM8TO1t97xJT0/jxvXruHdQ/qRKNe93wjLMKiA8PT05fPgwfn5+eS4/fPgwHh6mT0i0tbXN1V35uOELgNBgb6ysrLh4K5mKnk5M6VWbizeTWbH3EgBffneab0Y047fIGPafiaJV9TK0q/0CbcZvN2yjV/NKnL+RTFzKXepVKcmMfvWYvfUsl26lmMz8rNLT0rj20KeCmzducD4yEmdnZ7y8vfP99R/H0bFYrnFJewcHSjiXUM14Za8+fRn70Wj8/QMICAxi5YrlZGRk0KlzF9NPzmdqb7+pkyawfdtWvpw1F0cHR+Ju3wagWPHi2NkVzPegPIra207Nxy3A559Op0mz5nh5e3M7NpZ5c2ah0VjTpt1LSkdT9X73RKQHwiSzCoj333+ft956i2PHjtGyZUtDsRATE8Pu3btZtGgRn332Wb4EdXKwYUJYLUq7OZKYmsmWg1eZsOYY2dr75y/8cPgawxYd4L3OQXzWtx6XbiXz2md7OXA+1rCNyt7OTHitFi7FbLl6O5VPN51i1taz+ZI3p7Nnz/Bm396Gx5/NiADg5Y6dmTR1WoFkeJ61aduOxIQE5s6eSVzcbXz9qjJ3wde4qWAIQ+3Wr1sDQP83ehnNnzg5go4qKMDUTO3HbUxMNOEfjCQpKQkXV1dq1KjFN6vW4+rqqnS053+/s5ZzIEyx0uvNO4Nw3bp1fPHFFxw7dgyt9v4lkRqNhlq1ajFy5Eh69OjxVEEcuy19qucVhPi1fZWOIIQoZNR+7rbazyG0y+dvMbJvPsli28rYO9Zi21ITs9+CV155hVdeeYV79+4RFxcHgLu7O0WLPn4IQgghhHhuyBCGSU9dwxUtWhQvLy9LZhFCCCHUQe1dMCogJZYQQgghzPZc3AtDCCGEKFAyhGGSFBBCCCFETjKEYZKUWEIIIYQwm/RACCGEEDnJEIZJUkAIIYQQOckQhklSQAghhBA5SQ+ESdJCQgghhDCb9EAIIYQQOckQhklSQAghhBA5yRCGSdJCQgghhErs37+fDh064O3tjZWVFVu2bDFartfrGTduHF5eXtjb2xMaGsqlS5eM1klISCAsLAwnJydKlChB//79SU1NNVrn1KlTNG7cGDs7O1544QVmzJhhdlYpIIQQQoicrKwsN5khLS2N4OBg5syZk+fyGTNmMHPmTObPn8+hQ4dwdHTkxRdf5O7du4Z1wsLCOHv2LLt27WLr1q3s37+ft956y7A8JSWF1q1bU65cOY4dO8ann37KJ598wsKFC81rInNv551f7mYrneDRXOoMUTrCYyUema10BCFURx2/2R5NhtifTb7fzvsly/1ezdj6dH9DrKys2Lx5M506dQLu9z54e3vz3nvv8f777wOQnJyMh4cHy5Yto2fPnkRGRlKtWjWOHDlC7dq1AdixYwft2rXjxo0beHt7M2/ePD7++GOio6OxsbEB4MMPP2TLli2cP3/+ifNJD4QQQgjxHLhy5QrR0dGEhoYa5jk7O1OvXj0OHDgAwIEDByhRooSheAAIDQ3F2tqaQ4cOGdZp0qSJoXgAePHFF7lw4QKJiYlPnEdOohRCCCFysuBJlJmZmWRmZhrNs7W1xdbW1qztREdHA+Dh4WE038PDw7AsOjqaUqVKGS0vUqQIrq6uRuv4+Pjk2saDZS4uLk+UR3oghBBCiJwseA5EREQEzs7ORlNERITSP+Ezkx4IIYQQIh+Fh4czcuRIo3nm9j4AeHp6AhATE4OXl5dhfkxMDNWrVzesExsba/S87OxsEhISDM/39PQkJibGaJ0Hjx+s8ySkB0IIIYTIycraYpOtrS1OTk5G09MUED4+Pnh6erJ7927DvJSUFA4dOkRISAgAISEhJCUlcezYMcM6e/bsQafTUa9ePcM6+/fv5969e4Z1du3aha+v7xMPX4AUEEIIIURuCl3GmZqayokTJzhx4gRw/8TJEydOcO3aNaysrBg+fDiTJ0/m+++/5/Tp0/Tu3Rtvb2/DlRpVq1alTZs2DBgwgMOHD/P7778zZMgQevbsibe3NwCvvfYaNjY29O/fn7Nnz7Ju3Tq++uqrXL0kpsgQhhBCCJGTQt9EefToUZo3b254/OCPep8+fVi2bBkffPABaWlpvPXWWyQlJdGoUSN27NiBnZ2d4TmrVq1iyJAhtGzZEmtra7p27crMmTMNy52dndm5cyeDBw+mVq1auLu7M27cOKPvingS8j0QT0C+B0KI5486frM9mnwPxLPJ9++B6Py1xbaVsflNi21LTaQHQgghhMhJKjyTpIAQQgghcrCSAsIkOYlSCCGEEGYrdAXE2tWraNuqBXVqBBLWszunT52y+Gs0rFmRjV8O5PLOKWQcn02HZkFGyzu2COaHuYO5sXc6GcdnE1SltNFyFycHPh/dnZObx5Jw4HMubpvI/z7ohlMxO6P1/vdBN35f9QFJh77g4NoPLf5z5FQQbfcs1Jpv8aIFvNajKyF1atCscQjDh77DP1cuKx3LiFrbDuDY0SMMfWcQoc0aEezvy57dPysdyWDenFlUD/A1mjp1aKN0rFzU/P4+sHjRQoL9fZkRMUXpKE/EysrKYlNhVagKiB3bt/HZjAgGvjOYtRs24+vrx9sD+xMfH2/R13G0t+X0xZsMj1iX53IHexv+OPE3Y2ZuyXO5V0lnvEo6E/7FZmp1n8qA8Stp1aAa88eH5Vr3m+8OsnHnn5aMn6eCarunpeZ8R48c5pVXw1ixZj0LFi0lOzubQQP6k56ernQ0QN1tB5CRkY6vry/hY8YrHSVPFStV5udffjNMS79ZrXQkI2p/fwHOnD7Fxg1rqVLFV+koT87KglMhVagKiBXLl9KlWw86de5KxUqVGDN+AnZ2dmz5dpNFX2fn7+eYMHcr3+/Nu8pf8+MRIhbuYM/BC3kuP/d3FK++/zXb9p/hyo049h25yCezf6BdkwA0mn/fkvdmbGTB+v1cuZH/vwgKqu2elprzzVu4mI6du1CpUmV8/fyYOGUaUVG3iDx3VulogLrbDqBR46YMGTaClqGtlI6SJ41Gg7t7ScPk4uKqdCQjan9/09PSCB89ivETJuPk7Kx0HGFBhaaAuJeVReS5s9QPaWCYZ21tTf36DTh18riCyZ6MU3E7UtLuotXqCvy11d52as+XU+qdOwCq+GX5vLWdGl27dpVWzRvRvk1Lwke/R1TULaUjGTwP7+/UyRNp0qSpUcbngQxhmFZoCojEpES0Wi1ubm5G893c3IiLi1Mo1ZNxK+FI+IC2LNn0hyKvr/a2U3u+h+l0OmZMn0r1GjWpXLmK0nGeq7ZTo8CgICZOjmDO/K/5eOwn3Lxxk369w0hLS1U6GqD+93f7th+JjDzHuyPeUzqK2aSAMM3il3Fev36d8ePHs2TJkkeuk9etTfUa829tWhgUd7Rj88y3ibwcxeQFPyodRzyjqZMn8PelSyxboa5xcvF0GjVuavh/FV8/AgKDade6OTt3bKdz1+4KJlO/6KgoZkybwoJFS/6Tv9v/CyzeA5GQkMDy5csfu05etzb9dPqz3drUpYQLGo0m14lD8fHxuLu7P9O280sxB1u+n/MOd9Lv8srIRWRnF/zwBai/7dSe74Gpkyeyf98vLFq6HA8z7miXn56XtnteODk5UbZcea5fu6Z0FEDd7++5c2dJiI+nZ/cu1AyqRs2gahw9cpjVq1ZQM6gaWq1W0XymSA+EaWb3QHz//fePXX75sunL1/K6tale82wValEbG6pW8+fQwQO0aBkK3O9OPnToAD1fff2Ztp0fijva8cPcwWRmZdNt+AIys5T7Lm+1t53a8+n1eiKmTGLP7l0sXraCMmVeUDqSgdrb7nmTnp7GjevXce9QUukogLrf33r167Nxyw9G88Z/HE75ChXo238AGo1GoWRPpjD/4bcUswuITp06YWVlxeNuoWGq4W1tcw9XWOJeGL369GXsR6Px9w8gIDCIlSuWk5GRQafOXZ594w9xtLeh4gv//gIpX9qNoCqlSUxJ53p0Ii5ODrzg6YJXqfsn0VUp7wFATHwKMfF3KO5ox9a5g7G3s6Hvx8txcrTDyfH+d0DcTkxFp7vfthVecKeYvS0e7k7Y2xY1fJ9E5OVo7mVbtnovqLZ7WmrON3XSBLZv28qXs+bi6OBI3O3bABQrXtzoBjdKUXPbwf2z9K899In+5o0bnI+MxNnZGa//v3ugUj7/dDpNmjXHy9ub27GxzJszC43GmjbtXlI018PU+v46OhbLdR6QvYMDJZxLqOL8IJOkfjDJ7ALCy8uLuXPn0rFjxzyXnzhxglq1aj1zsKfRpm07EhMSmDt7JnFxt/H1q8rcBV/jZuGuvJrVyrHz62GGxzPe7wrAiu8P8tb4lbRvGsiiib0My1dM7wfA5PnbmLJgG9X9XqBukA8A5374xGjbvu3GcS0qAYB548JoUruyYdmhdeG51rGUgmq7p6XmfOvXrQGg/xu9jOZPnBxBRxX8kVZz2wGcPXuGN/v2Njz+bMb94cyXO3Zm0tRpSsUCICYmmvAPRpKUlISLqys1atTim1XrcXVVz6Wcan9/ReFl9t04X375ZapXr87EiRPzXH7y5Elq1KiBTmfeeL7cjfPpyd04hchN7sZZuOX33ThLhK202LaSVhXO4UKz34JRo0aRlpb2yOWVKlVi7969zxRKCCGEUJKcA2Ga2QVE48aNH7vc0dGRpk2bPnYdIYQQQjzf5HbeQgghRA7SA2GaFBBCCCFEDlJAmFZovspaCCGEEAVHeiCEEEKInKQDwiQpIIQQQogcZAjDNBnCEEIIIYTZpAdCCCGEyEF6IEyTAkIIIYTIQQoI06SAEEIIIXKS+sEkOQdCCCGEEGaTHgghhBAiBxnCME0KCCGEECIHKSBMkwLiCaj9dtkundSdL3GLum+HLgonvcrv5y1/oMTzTgoIIYQQIgcp8EyTAkIIIYTIQQoI0+QqDCGEEEKYTXoghBBCiJykA8IkKSCEEEKIHGQIwzQZwhBCCCGE2aQHQgghhMhBeiBMkwJCCCGEyEEKCNOkgBBCCCFykvrBJDkHQgghhBBmkx4IIYQQIgcZwjCtUPVAHDt6hKHvDCK0WSOC/X3Zs/tnpSM90uJFCwn292VGxBSLb7uhvzcbx7Xn8vK+ZGwdQof6PrnWGRtWl8vf9CVh0yB+nNyRit7ORstditmy9P1WxKx/i6i1A5j3bgsc7Yoaln/8Wl0ytg7JNcVtHGjxnyen/Gw7S1BjvrWrV9G2VQvq1AgkrGd3Tp86pXQkAzUdt8eOHmHYkEG0atGYGoF+7M0jy+XLfzNs6Ns0DqlNSN0ahPXsRlTULQXSGlPjfgfq3vcex8rKymJTYVWoCoiMjHR8fX0JHzNe6SiPdeb0KTZuWEuVKr75sn1HuyKcvhzH8Pn78lz+XteavNMhmHfn/EKT9zaQdvceP0x8GduiGsM6S99vTdWyrrw05ju6TtxKowBv5gxpblj+5bfHKf/6EqPp3NV4vv3tr3z5mR7I77Z7VmrMt2P7Nj6bEcHAdwazdsNmfH39eHtgf+Lj45WOBqjruM3IyKBKFT/CPx6X5/Lr16/Rr/dr+PhUYNGSb1i/6TsGDHwHWxvbAk5qTI37Hah/3xPPplAVEI0aN2XIsBG0DG2ldJRHSk9LI3z0KMZPmIyTs7PpJzyFnceuMWHlIb4/cDnP5YM7BjN93VG2HrrCmX/iefPzn/FydeTlkAoA+JZx4cXa5Xhn5l6OXIzhj3NRjJy/n+5NKuPl6ghA2t17xCSlG6ZSLvZUK+fG8l3n8uVngoJpu2eh1nwrli+lS7cedOrclYqVKjFm/ATs7OzY8u0mpaMB6jpuGzVuwuB3h9OiZd5ZZs/8kkaNmzJ85Cj8qlbjhRfK0qx5C1zd3Ao46b/Uut+B+ve9x5EeCNMKVQHxPJg6eSJNmjSlfkgDRV6/vIcTXq6O7Dlx3TAvJT2LIxdiqOfnCUC9qp4kpt7lz79iDevsOXEdnV5PHV+PPLfbt7U/F28k8vvZqHzLrnTbmaLGfPeysog8d9Yok7W1NfXrN+DUyeMKJnv+6HQ6ftv/C2XLleedgf1p0bQBvV7rkecwR0FS434Hz/++JwWEaVJAFKDt234kMvIc7454T7EMni4OAMQmpRvNj01Kx6PE/WUeJRy4nZRhtFyr05Nw565hnYfZFtXwSrMq+dr7oIa2exy15ktMSkSr1eKW4xOym5sbcXFxCqV6PiUkxJOens7SJYto0LAx8xYspnmLUN4bMZSjRw4rkkmt+x3IvvdfYPZVGBkZGRw7dgxXV1eqVatmtOzu3busX7+e3r17P3YbmZmZZGZmGs3Ta2yxtVV2HDE/RUdFMWPaFBYsWlLofs6OIRUobl+UlbvP58v21d52as8nLEOn0wHQrFkLXu/9BgC+flU5efI4GzespXadugWaR/a7fFZ4Ow4sxqweiIsXL1K1alWaNGlCYGAgTZs2JSrq3y7r5ORk+vbta3I7ERERODs7G02fTo8wP/1z5Ny5syTEx9OzexdqBlWjZlA1jh45zOpVK6gZVA2tVlsgOaIT7/c8lMrRk1CqhAMx/98rEZOUTskS9kbLNdZWuBa3M6zzsDderMb2I/8Qm6PXwlLU0nbPYz6XEi5oNJpcJ63Fx8fj7u6uUKrnk4uLC0WKFKFCxUpG8yv4VCQ6Kv+G7h5FzfsdPP/7ngxhmGZWD8To0aMJCAjg6NGjJCUlMXz4cBo2bMgvv/xC2bJln3g74eHhjBw50mieXlO4K+h69euzccsPRvPGfxxO+QoV6Nt/ABqN5hHPtKx/YlKISkijefUynLpyvxuxuH1R6vh6sGj7GQAORUbjUsyOGhVLcvzv2wA0Cy6DtZUVRy7EGG2vnEdxmgaWodukH/Mts1ra7lHUnK+ojQ1Vq/lz6OABWrQMBe5/kj506AA9X31dsVzPo6JFbajmH8DVf64Yzb969R+8vLwLPI+a9zuQfe+/wKwC4o8//uDnn3/G3d0dd3d3fvjhB9555x0aN27M3r17cXR0fKLt2NrmHq64m21Okrylp6Vx7do1w+ObN25wPjISZ2dnvLwL/gB/mKNjMSpXrmI0z97BgRLOJXLNf+bXsitKRa9/z8Yu7+FEkI87ial3uX47lTnfnWT0K7X562YS/8TcYfzr9YhKSDNctXHhRiI/Hb3KnKHNeXfuLxTVWPPFoKZs2H+JqIQ0o9fq06oa0Ylp/HTsqkV/BqOfpwDb7mmoPV+vPn0Z+9Fo/P0DCAgMYuWK5WRkZNCpcxelowHqOm7T09O4/nCWmze4cD4SJ2dnvLy86dO3P6PfH0nNWrWpXbcef/z2K/v37WXRkm8KNCeof78D9e97j1OYew4sxawCIiMjgyJF/n2KlZUV8+bNY8iQITRt2pTVq1dbPKA5zp49w5t9/z3/4rMZ94dFXu7YmUlTpykVq8DVrFyKnRGdDY9nDGgMwIqfI3nry938b9OfONgVYfbQ5pRwtOWPc1G8PO4HMu/92+XZ97OdfDGoKdsmd0Kn17Plj795b8GvRq9jZQW9Wvqx4ufz6HT6gvnhhNnatG1HYkICc2fPJC7uNr5+VZm74GvcVNKNrKbj9tzZMwzo18fw+H+f3n/9Di93YuKUabRo2YqPx33Ckq8XMmPaFMqV9+HTz2dSo2atAs35vFD7vvc4Uj+YZqXX65/4N3/dunUZOnQovXr1yrVsyJAhrFq1ipSUlKcae7NED8R/lUun2UpHeKzELUOUjiD+g9Re1Fpby1+oZ2GXzzdiqDxqh8W2denTNhbblpqYdRJl586dWbNmTZ7LZs+ezauvvooZ9YgQQgghnlNm9UDkJ+mBeHrSAyFEbtIDUbjldw9ElQ8s1wNxcUbh7IGQu3EKIYQQOchJlKbJN1EKIYQQwmxSQAghhBA5WFlZbjKHVqtl7Nix+Pj4YG9vT8WKFZk0aZLR+YV6vZ5x48bh5eWFvb09oaGhXLp0yWg7CQkJhIWF4eTkRIkSJejfvz+pqamWaBoDKSCEEEKIHKytrSw2mWP69OnMmzeP2bNnExkZyfTp05kxYwazZs0yrDNjxgxmzpzJ/PnzOXToEI6Ojrz44ovcvXvXsE5YWBhnz55l165dbN26lf379/PWW29ZrH1AzoEQQgghVOOPP/6gY8eOtG/fHoDy5cuzZs0aDh++f8M2vV7Pl19+yZgxY+jYsSMA33zzDR4eHmzZsoWePXsSGRnJjh07OHLkCLVr1wZg1qxZtGvXjs8++wxvC31Bm/RACCGEEDkoNYTRoEEDdu/ezcWLFwE4efIkv/32G23btgXgypUrREdHExoaaniOs7Mz9erV48CBAwAcOHCAEiVKGIoHgNDQUKytrTl06NAztsy/pAdCCCGEyMGSV2HkdQfqvG7pAPDhhx+SkpKCn58fGo0GrVbLlClTCAsLAyA6OhoADw8Po+d5eHgYlkVHR1OqVCmj5UWKFMHV1dWwjiVID4QQQgiRj/K6A3VERN53oF6/fj2rVq1i9erV/PnnnyxfvpzPPvuM5cuXF3Bq06QHQgghhMjBkl8DkdcdqPPqfQAYNWoUH374IT179gQgMDCQq1evEhERQZ8+ffD09AQgJiYGLy8vw/NiYmKoXr06AJ6ensTGxhptNzs7m4SEBMPzLUF6IIQQQogcrKysLDbZ2tri5ORkND2qgEhPT8fa2vhPs0ajQafTAeDj44Onpye7d+82LE9JSeHQoUOEhIQAEBISQlJSEseOHTOss2fPHnQ6HfXq1bNYG0kPhBBCCJGDUt9E2aFDB6ZMmULZsmXx9/fn+PHjfP755/Tr18+Qa/jw4UyePJnKlSvj4+PD2LFj8fb2plOnTgBUrVqVNm3aMGDAAObPn8+9e/cYMmQIPXv2tNgVGCAFhBBCCKEas2bNYuzYsbzzzjvExsbi7e3NwIEDGTdunGGdDz74gLS0NN566y2SkpJo1KgRO3bswM7OzrDOqlWrGDJkCC1btsTa2pquXbsyc+ZMi2aVm2mJfOfSdYHSER4pcdNApSM8lk4dh+cjWcv9Ap6ayt9a1d9Z2cEmf/e96p/sNr3SEzrxSUuLbUtNpAdCCCGEyEFupmWanEQphBBCCLNJD4QQQgiRg3RAmCYFhBBCCJGDDGGYJkMYQgghhDCb9EAIIYQQOUgHhGlSQAghhBA5yBCGaTKEIYQQQgizSQ+EEEIIkYN0QJgmBYQQQgiRgwxhmCYFhBBCCJGD1A+mFZpzIBYvWsBrPboSUqcGzRqHMHzoO/xz5bLSsQyOHT3C0HcGEdqsEcH+vuzZ/bPSkYwo2X7F7Ivyaf8GXFj0Ggnr+7N3ekdqVSppWF7K2Z6F7zbj8tLXiV/fj+/Gt6Oil5PRNmyLavhiYCNurOjD7bX9WDO6FaWc7Qsk/wNrV6+ibasW1KkRSFjP7pw+dapAX/+BY0ePMGzwIFo1b0yNAD/25tjX9Ho9c2fPpFWzxtSvFczAN/ty9eo/imQFdR8b69euplvnDjSoW5MGdWvS67VX+O3XfUrHMpg3ZxbVA3yNpk4d2iiS5djRIwwbMohWLRpTIzD3fvewyRPHUyPQj1UrlhdgQmFphaaAOHrkMK+8GsaKNetZsGgp2dnZDBrQn/T0dKWjAZCRkY6vry/hY8YrHSVPSrbfvCFNaVG9NP2+2Evtdzfw8/Eb/DixPd6uDgCs/+hFfDyd6D7lJ+qP2MS12Dtsm/gSDrb/dqDN6B9C+zplCZuxi9Yff4+XqyNrw1vne/YHdmzfxmczIhj4zmDWbtiMr68fbw/sT3x8fIFleCAjI4Mqvn6Efzwuz+XLlnzNmlUr+GjcJ3yzej329vYMHvgmmZmZBZz0PjUfG6U8PBk24n3WbPiW1es3UbdefYYNGcxff11SOppBxUqV+fmX3wzT0m9WK5IjIyODKlUevd89sGf3Lk6fOknJUqUKKNnTsbKysthUWBWaIYx5CxcbPZ44ZRrNG4cQee4stWrXUSjVvxo1bkqjxk2VjvFISrWfnY2GTiE+dJ/yE7+fiwJgytpjtKtTjgFt/Vm19yL1/DyoOWQ9kdcTAXh3/q/8s6w3PZpUYtmu8zg52PBGqB9vfL6bfadvAfDWzF84OfcV6lYpxeGLsfmW/4EVy5fSpVsPOnXuCsCY8RPYv/8Xtny7if4D3sr3139Yo8ZNaNS4SZ7L9Ho9q1d8w4C3BtG8xf07BE6aOp3Qpg3Zu/tn2rRrX5BRAXUfG82atzB6PHTYCNavXcOpkyeoVKmyQqmMaTQa3N1Lml4xnz1uv3sgNiaG6VMnM3fB1wwdrO474Rbiv/sWU2h6IHJKvXMHACdnZ4WTPJ8Kqv2KaKwporHm7j2t0fy7Wdk0qOqJbVHN/ccPLdfrIStbS4OqngDUqOiOTVENe07eNKxz8WYS12LvUM/PI1/zA9zLyiLy3FnqhzQwzLO2tqZ+/QacOnk831/fHDdv3CAu7jb1HspavHhxAoKCOHXyhHLBngNarZbt234kIyOd4OAaSscxuHbtKq2aN6J9m5aEj36PqKhbSkfKk06nY8xHH9Cnb38qqqT4Es+m0PRAPEyn0zFj+lSq16hJ5cpVlI7z3CnI9kvNuMfB89GE96jJhRuJxCRl0KNxJer5evB3dAoXbtwvBCb1qsuQuftJy8zm3ZcDKeNeDM//H+LwdHEg856W5LQso23HJmXgUcIhX/MDJCYlotVqcXNzM5rv5ubGFRWdhwMQF3cbANdcWd2Jj4tTIpLqXbp4gV6v9SQrKxMHBwe+mDmHipUqKR0LgMCgICZOjqB8eR/i4m4zf+4c+vUOY+OWH3B0LKZ0PCNLlyxCo9HwalgvpaM8kcI89GApZhcQkZGRHDx4kJCQEPz8/Dh//jxfffUVmZmZvP7667Ro0cLkNjIzM3ONt+o1ttja2pobJ09TJ0/g70uXWLZCmbHA511Bt1+/L/ayYGhTLi/tRbZWx4m/41j/69/UqOhOtlZHz2k7mTekKVGr+5Kt1bHn5E12HL0mXYyiQJQv78P6TVtITb3Drp0/Mfaj0SxetlIVRcTDQz9VfP0ICAymXevm7Nyxnc5duyuYzNi5s2dYs3IFq9dvem7+MD8nMRVlVgGxY8cOOnbsSLFixUhPT2fz5s307t2b4OBgdDodrVu3ZufOnSaLiIiICCZMmGA07+Ox4xkz7hOzf4Ccpk6eyP59v7Bk+Uo8PD2feXv/NUq035XoFFp//AMOtkVwcrAhOjGdFaNCuRKTAsDxv+OoP2ITTg422BSxJi7lLvs/7cSxv+5/Yo5OTMe2qAZnRxujXohSJeyJScr/k0BdSrig0WhynTAZHx+Pu7t7vr++OR6MlSfEx1Oy5L8nscXHx+HrW1WpWKpW1MaGsuXKAVDNP4CzZ06zauU3jPtkosLJcnNycqJsufJcv3ZN6ShGjv95jISEeNq1/vdvg1ar5fPPprNq5XK2/bRHwXTiaZl1DsTEiRMZNWoU8fHxLF26lNdee40BAwawa9cudu/ezahRo5g2bZrJ7YSHh5OcnGw0jRod/tQ/BNw/OWzq5Ins2b2LRUuWU6bMC8+0vf8aNbRfemY20YnplHC0IbR6GbYeumq0PCU9i7iUu1T0cqJmxZJsPfQPcL/AyLqnpXlQacO6lUs7U7ZUcQ6dj8n33EVtbKhazZ9DBw8Y5ul0Og4dOkCQisbKAUqXKYO7e0mjrKmpqZw5dYqg4OrKBXuO6HQ67mVlmV5RAenpady4fh33ksqfVPmw9h1eZv2m71i7YbNhKlmqFL3f6M/c+V8rHS9PchWGaWb1QJw9e5ZvvvkGgB49etCrVy+6detmWB4WFsbSpUtNbsfWNvdwxd1sc5LkNnXSBLZv28qXs+bi6OBI3O37Y73FihfHzs7u2TZuAelpaVx76FPBzRs3OB8ZibOzM17e3gomu0/J9gutUQYrrLh4M4mKXk5MfaM+F28m8c3uCwB0aVCB2ykZXL+dSkA5Vz57syE/HPqH3SduAPcLi2U/n2d6vxASUjO5k57F52815OD56AK5AgOgV5++jP1oNP7+AQQEBrFyxXIyMjLo1LlLgbz+w9LT04w+gd68eYML5yNxcnbGy8ub13r15uuF8ylbrjylS5dm7uyZlCxViuYtQws8K6j72Pjqi//RqHETPL28SE9LY9uPWzl65HCuq5aU8vmn02nSrDle3t7cjo1l3pxZaDTWtGn3UoFnMbXflSjhYrR+kSJFcHd3p7xPhYKO+kQK8x9+SzH7HIgHjWptbY2dnR3OD52lX7x4cZKTky2Xzgzr160BoP8bxifoTJwcQUcFfonndPbsGd7s29vw+LMZEQC83LEzk6aa7rXJb0q2n7ODDRN71aW0ezES7tzluwNXGL/yCNlaHQCerg5M7x9CKWd7ohPTWbX3IhHr/zTaxgeLD6DTw5rRrbAtquHn4zcYNv/XfM39sDZt25GYkMDc2TOJi7uNr19V5i74GjcFhjDOnTnDgH59DI//N+P+/tWhYycmTpnGG/3eJCMjg8mfjOPOnRSq16zFnPmLLHYOkrnUfGwkJMQzJnw0t2/HUqx4capU8WXewsWENGioaK4HYmKiCf9gJElJSbi4ulKjRi2+WbUeV1fXAs9y7myO/e7T/9/vXr6/34nCx0qv1+ufdOXg4GCmT59Omzb3v+nszJkz+Pn5UaTI/Trk119/pU+fPly+bP6Z58/aAyHUy6XrAqUjPFLiJnVfi6578sNTEdbyKe2pqfytxYw/DYpwsMnffa/pF79bbFv7Rqij4LQ0s3og3n77bbTaf6/HDwgIMFq+ffv2J7oKQwghhFAzGcIwzawCYtCgQY9dPnXq1GcKI4QQQqiB1A+mFdpvohRCCCFE/imU30QphBBCPAsZwjBNCgghhBAiB6kfTJMhDCGEEEKYTXoghBBCiBzkEmXTpIAQQgghcpD6wTQZwhBCCCGE2aQHQgghhMhBrsIwTQoIIYQQIgdrqR9MkgJCCCGEyEF6IEyTcyCEEEIIYTbpgRBCCCFykA4I06SAKARUftddVd8y26P3CqUjPFbMN72UjiDyidr/QKn810q+s0Llb5AKyBCGEEIIIcwmPRBCCCFEDnIVhmlSQAghhBA5yFUYpskQhhBCCCHMJj0QQgghRA7SAWGaFBBCCCFEDnI3TtNkCEMIIYQQZpMeCCGEECIH6YAwTQoIIYQQIge5CsM0KSCEEEKIHKR+ME3OgRBCCCGE2QpVAXHs6BGGvjOI0GaNCPb3Zc/un5WOlMva1ato26oFdWoEEtazO6dPnVI6EgDz5syieoCv0dSpQxulYxlRqu2K2RUholdtTn/Vmehlr7LzkxepWcEtz3W/6FeP5NW9eLuNn9H8U191Jnl1L6NpRAf/goj/XBwXDyxetJBgf19mRExROooRtR63D1Nj26WlpfLptKm0bdWC+rWC6RPWk7OnTysd64lYW1lZbCqsClUBkZGRjq+vL+FjxisdJU87tm/jsxkRDHxnMGs3bMbX14+3B/YnPj5e6WgAVKxUmZ9/+c0wLf1mtdKRDJRsu1kDQmge6MXAeb/TYPRW9pyOYstHoXi52But91LtF6hdyZ1bCel5bmfyhhNUfnuDYVqw80K+Zwf1HxcPnDl9io0b1lKliq/SUYyo/bgF9bbdxHFjOXjgDyZHTGf95u8JadCQQQP6EhsTo3Q0k6wsOBVWhaqAaNS4KUOGjaBlaCulo+RpxfKldOnWg06du1KxUiXGjJ+AnZ0dW77dpHQ0ADQaDe7uJQ2Ti4ur0pEMlGo7u6IaXq5blnGr/+SP87FcjrnDtE2nuBJzh/6h//6y9nKxZ0afOgyY8xv3tLo8t5WacY/Y5LuGKT0zO1+zP6D24wIgPS2N8NGjGD9hMk7OzkrHMaL241atbXf37l12/7yT4SPfp1btOpQtW45Bg4fyQtmybFi3Rul4wgIsUkDo1X4/aRW4l5VF5Lmz1A9pYJhnbW1N/foNOHXyuILJ/nXt2lVaNW9E+zYtCR/9HlFRt5SOBCjbdkU0VhTRWJN5T2s0PyNLS33fksD9k60WvtOImT+e4/zN5Edua8TLAVxZ0INfp7bn3ZeqoZG79RhMnTyRJk2aGr3HavA8HLdqbTutNhutVouNra3RfFtbO47/eUyhVE/OysrKYlNhZZGrMGxtbTl58iRVq1a1xOYKpcSkRLRaLW5uxmPnbm5uXLlyWaFU/woMCmLi5AjKl/chLu428+fOoV/vMDZu+QFHx2KKZlOy7VLvZnPoYiyjOgdy4WYyscl36dagPHUru3M5+g4AIzoEkK3VMX/H+UduZ8FP5zl5JYHE1EzqVSnJ+J418Chhz8cr1f+LNL9t3/YjkZHnWL1uo9JRclH7cavmtnN0LEZQcHUWzZ+LT4UKuLm5s2Pbj5w6eYIXypZVOp5JUt+bZlYBMXLkyDzna7Vapk2bZjjIPv/888duJzMzk8zMTKN5eo0ttjkqVVFwGjVuavh/FV8/AgKDade6OTt3bKdz1+4KJlPewLm/M3tgAy7M7Ua2VsfJfxLY+Mc/VPdxo7qPK4Pa+NHkox8fu4052yIN/z97PYmsbB1f9q/PhLXHycrOe8jjvyA6KooZ06awYNESOf7N9Dy03eSIGXwy7iNebNEUjUaDX9VqtGnbnshzZ5WOJizArALiyy+/JDg4mBIlShjN1+v1REZG4ujo+ETdNREREUyYMMFo3sdjxzNm3CfmxHmuuJRwQaPR5DrxKj4+Hnd3d4VSPZqTkxNly5Xn+rVrSkdRvO2uxKbSftJOHGyLUNy+KDFJGSwd2ph/Yu8Q4luKkk52nJ3VxbB+EY01U16vxdttqxI0bHOe2zz6VxxFi1hTtmQx/opKyfefQa3OnTtLQnw8Pbv/235arZZjR4+wds0qjhw/jUajUSyf0vve46i97QBeKFuWxctWkpGeTmpaKiVLlmL0eyMoXeYFRXM9icI89GApZp0DMXXqVJKTkxk7dix79+41TBqNhmXLlrF371727Nljcjvh4eEkJycbTaNGhz/1D/E8KGpjQ9Vq/hw6eMAwT6fTcejQAYKCayiYLG/p6WncuH4d95IllY6imrZLz8wmJimDEo42tAjyZtuxG6z97TINPtxKo/AfDdOthHRmbj1Hl2m7H7mtwPKuaHU64lLuFlh+NapXvz4bt/zAuk1bDJO/fwDtXurAuk1bFP8DqJZ9Ly9qb7uH2Ts4ULJkKVKSk/njj99o1qKF0pFMsrKy3GSumzdv8vrrr+Pm5oa9vT2BgYEcPXrUsFyv1zNu3Di8vLywt7cnNDSUS5cuGW0jISGBsLAwnJycKFGiBP379yc1NfVZm8WIWT0QH374IS1btuT111+nQ4cOREREULRoUbNf1NY293DFXQuckJ6elsa1hz4x37xxg/ORkTg7O+Pl7f3sL/CMevXpy9iPRuPvH0BAYBArVywnIyODTp27mH5yPvv80+k0adYcL29vbsfGMm/OLDQaa9q0e0npaICybdcyyAuw4q+oFCp4FGfiazW5dCuZlfv+IlurJzE1y2j9e1odMUkZhp6FOpXdqV3RnV/PxZB69x51Kpck4vXarPvtCklpWXm8omWp+bhwdCxG5cpVjObZOzhQwrlErvlKUetx+zy03R+//4peD+XL+3D92lW++N+n+PhU4OVOyv/OU6vExEQaNmxI8+bN2b59OyVLluTSpUu4uLgY1pkxYwYzZ85k+fLl+Pj4MHbsWF588UXOnTuHnZ0dAGFhYURFRbFr1y7u3btH3759eeutt1i92nKX55t9EmWdOnU4duwYgwcPpnbt2qxatUo1XT1nz57hzb69DY8/mxEBwMsdOzNp6jSlYhm0aduOxIQE5s6eSVzcbXz9qjJ3wde4qWAIIyYmmvAPRpKUlISLqys1atTim1XrcXVVx6WcSradk70N43vWwNvVgcTUTL4/co1J606QrX2yq4+y7unoGlKeD7sGY1vUmquxqczdHsnsbefyOfl9aj8u1E7Nx63apd5JZdaXnxMTE42zcwlatmrF4HdHPNUHz4Km1N+16dOn88ILL7B06VLDPB8fH8P/9Xo9X375JWPGjKFjx44AfPPNN3h4eLBlyxZ69uxJZGQkO3bs4MiRI9SuXRuAWbNm0a5dOz777DO8LfTBwUr/DNdgrl27luHDh3P79m1Onz5NtWrVnjqIJXog/qvUfhWtSurLPHn0XqF0hMeK+aaX0hHEf5RO5b9YHIrm7y+WN9ZY7ttGF3TxzXXhQF498QDVqlXjxRdf5MaNG+zbt4/SpUvzzjvvMGDAAAAuX75MxYoVOX78ONWrVzc8r2nTplSvXp2vvvqKJUuW8N5775GYmGhYnp2djZ2dHRs2bKBz584W+bme6XsgevbsydGjR/n2228pV66cRQIJIYQQSrPk90BERETg7OxsNEVEROT5upcvX2bevHlUrlyZn376ibfffpt3332X5cuXAxAdHQ2Ah4eH0fM8PDwMy6KjoylVqpTR8iJFiuDq6mpYxxKe+XsgypQpQ5kyZSyRRQghhCh0wsPDc30NwqMuvdXpdNSuXZupU6cCUKNGDc6cOcP8+fPp06dPvmc1R6H6KmshhBDCEix5LwxbW1ucnJyMpkcVEF5eXrlOB6hatarhRGhPT08AYnLcTyQmJsawzNPTk9jYWKPl2dnZJCQkGNaxBCkghBBCiByUuhtnw4YNuXDB+EZ7Fy9eNJwm4OPjg6enJ7t3/3uZeEpKCocOHSIkJASAkJAQkpKSOHbs32+63bNnDzqdjnr16j1tk+Rika+yFkIIIcSzGzFiBA0aNGDq1Kn06NGDw4cPs3DhQhYuXAjcPzdj+PDhTJ48mcqVKxsu4/T29qZTp07A/R6LNm3aMGDAAObPn8+9e/cYMmQIPXv2tNgVGCAFhBBCCJGLUleP1alTh82bNxMeHs7EiRPx8fHhyy+/JCwszLDOBx98QFpaGm+99RZJSUk0atSIHTt2GL4DAmDVqlUMGTKEli1bYm1tTdeuXZk5c6ZFsz7TZZyWJJdxPj11vIOPJpdxPj25jFMo5b9+GedbGyx3v46F3f0tti01kXMghBBCCGE2GcIQQgghclBzz6laSAEhhBBC5GDu1RP/RTKEIYQQQgizSQ+EEEIIkYN0QJgmBYQQQgiRg1ruMq1mUkAUArKfPz21XyZZefh3Skd4rEtfdlQ6gsgn//VzAGR83zRpIyGEEEKYTXoghBBCiBxkCMM0KSCEEEKIHKylfjBJhjCEEEIIYTbpgRBCCCFykB4I06SAEEIIIXKQcyBMkyEMIYQQQphNeiCEEEKIHGQIwzQpIIQQQogcZATDNBnCEEIIIYTZpAdCCCGEyOG//lXeT0IKCCGEECIH6Z43rVAVEMeOHmHZksVEnjvD7du3+WLmHFq0DFU6FqDubA+sXb2K5UsXExd3myq+fnz40VgCg4KUjsXiRQvYvWsnV65cxtbOjurVazB85PuU96mgdDQjSrSftRWMbOdH5zplKOVkR0zyXTYcusZXOy4arVfJoxgfdapGvUruFLG24lL0Hd76+gi3EjMo42rPgYmt89z+oMVH+PH4rXzLv37tatavW8OtmzcBqFipMgPffodGjZvm22uaQ+3Hrdrb72GLFy1k5pf/I+z13nwQ/rHScUySDgjTClWRlZGRjq+vL+FjxisdJRc1ZwPYsX0bn82IYOA7g1m7YTO+vn68PbA/8fHxSkfj6JHDvPJqGCvWrGfBoqVkZ2czaEB/0tPTlY5moFT7vdOqMr0al2fshtM0n7ybqd+dZVBoZfo2/be4KufuwLcjG/NXdCo9vvqd1hF7+WrHRTLvaQG4lZhBzfAdRtNnWyNJvZvN3rMx+Zq/lIcnw0a8z5oN37J6/Sbq1qvPsCGD+euvS/n6uk9K7cet2tvvgTOnT7Fxw1qqVPFVOoqwoELVA9GocVNVVt6g7mwAK5YvpUu3HnTq3BWAMeMnsH//L2z5dhP9B7ylaLZ5CxcbPZ44ZRrNG4cQee4stWrXUSiVMaXar1YFV3aeimbP//+hv5GQQcfasVQvV8KwzgcdqrLnbAxTvztnmHc17t/iS6eH23cyjbbbJtiLrX/eJD1Lm2/ZAZo1b2H0eOiwEaxfu4ZTJ09QqVLlfH3tJ6H241bt7QeQnpZG+OhRjJ8wmUUL5ikd54nJORCmFaoeCPF07mVlEXnuLPVDGhjmWVtbU79+A06dPK5gsryl3rkDgJOzs8JJ7lOy/Y5dTqChb0l8SjkCULW0E3UquLL3XCxwvxu2hb8nV2JTWTk4hOMRbfj+/Sa8GOT5yG0GvuBMwAslWHvgar5mz0mr1bJ9249kZKQTHFyjQF+7MFBr+02dPJEmTZoaHR/PAysry02FVaHqgRBPJzEpEa1Wi5ubm9F8Nzc3rly5rFCqvOl0OmZMn0r1GjWpXLmK0nEAZdtvzq5LFLMryi9jWqLV69FYWTFjayRbjt4AwL2YLcXsivBOq8p8ujWSqVvO0qyaBwvfrMsrM3/n4F+5h1h6hpTjYtQdjl1JzNfsD1y6eIFer/UkKysTBwcHvpg5h4qVKhXIaxcGam6/7dt+JDLyHKvXbVQ6isgHz1RApKWlsX79ev766y+8vLx49dVXc/0SzUtmZiaZmcZdpnqNLba2ts8SR/wHTJ08gb8vXWLZitVKR1GFDjVL07lOGYYuP8bFqBSqlXbmk26BxCTfZeOh61j//9fp7Twdzdd77xcz526mULuCC683Kp+rgLArak3H2mWYueNCgf0M5cv7sH7TFlJT77Br50+M/Wg0i5etVM0fQbVTa/tFR0UxY9oUFixa8lz+bpdvojTNrCGMatWqkZCQAMD169cJCAhgxIgR7Nq1i/Hjx1OtWjWuXLlicjsRERE4OzsbTZ9Oj3i6n0A8M5cSLmg0mlwn/MXHx+Pu7q5QqtymTp7I/n2/sGjpcjw8H90FX9CUbL+PO/kzd9clvj92k/O37vDtkRt8vedvBre6P/6dkJrJPa2OS1F3jJ53KToVbxf7XNtrV90bexsNGw9fz9fcDytqY0PZcuWo5h/AsBHvUcXXj1Urvymw13/eqbX9zp07S0J8PD27d6FmUDVqBlXj6JHDrF61gppB1dBq8/f8mmdlbWVlsamwMquAOH/+PNnZ2QCEh4fj7e3N1atXOXz4MFevXiUoKIiPPzZ9eU54eDjJyclG06jR4U/3E4hnVtTGhqrV/Dl08IBhnk6n49ChAwSpYCxVr9czdfJE9uzexaIlyylT5gWlIxlRsv3sbTTodHqjeVq93tDzcE+r5+TVJCp4FDNap0KpYtxMzMi1vZ4NyrHrdDQJqVn5F9oEnU7HvSzlXv95p5b2q1e/Phu3/MC6TVsMk79/AO1e6sC6TVvQaDRKRxTP6KmHMA4cOMD8+fNx/v8T2YoVK8aECRPo2bOnyefa2uYerrib/bRJ/pWelsa1a9cMj2/euMH5yEicnZ3x8vZ+9hd4BmrOBtCrT1/GfjQaf/8AAgKDWLliORkZGXTq3EXpaEydNIHt27by5ay5ODo4Enf7NgDFihfHzs5O4XT3KdV+P5+OZuiLVbiZmMHFqBQCypRgQPOKrDv477624Oe/mNOvNof+iufAxTiaVitFaIAHPb763Whb5d0dqVfRjT7zDuZr5od99cX/aNS4CZ5eXqSnpbHtx60cPXI415U3SlH7cavm9nN0LJbrPCV7BwdKOJdQzflLj1OIOw4sxuwC4sE90u/evYuXl5fRstKlS3P7/3+5K+Hs2TO82be34fFnM+4Pi7zcsTOTpk5TKhag7mwAbdq2IzEhgbmzZxIXdxtfv6rMXfA1bioYwli/bg0A/d/oZTR/4uQIOqqgwAHl2m/shtO8/5IfU14Jwr2YLTHJd1n1+z98uf3fcxh2nIrio7UnGdy6MhO7BfJ3bCoDvz7CkcsJRtt6JaQsUUkZ7Dsfm6+ZH5aQEM+Y8NHcvh1LseLFqVLFl3kLFxPSoGGBZXgctR+3am+/55mcA2GalV6v15te7T5ra2sCAgIoUqQIly5dYtmyZXTt2tWwfP/+/bz22mvcuHHD7CCW6IEQorCpPPw7pSM81qUvOyodQfxH2eXzNYRTdv9lsW193LJwnhBs1lswfrzxt7EVK2Y8rvrDDz/QuHHjZ08lhBBCKMgK6YIw5ZkKiJw+/fTTZwojhBBCqIEMYZgmXyQlhBBC5CAFhGnyVdZCCCGEMJv0QAghhBA5WMl1nCZJASGEEELkIEMYpskQhhBCCCHMJj0QQgghRA4ygmGaFBBCCCFEDoX5JliWIkMYQgghhDCb9EAIIYQQOchJlKZJASGEEELkICMYpskQhhBCCCHMJj0QhcCT309VGWqu5NXedhe/UPfdLj16r1A6wiPFfNPL9EoKUvu+p+bjtiBYy820TJICQgghhMjhv15APQkpIIQQQogc5CRK0+QcCCGEEEKYTXoghBBCiBzki6RMkwJCCCGEyEHqB9NkCEMIIYQQZpMeCCGEECIHGcIwTQoIIYQQIgepH0yTIQwhhBBCmE16IIQQQogc5NO1aVJACCGEEDlYyRiGSVJkCSGEECo0bdo0rKysGD58uGHe3bt3GTx4MG5ubhQrVoyuXbsSExNj9Lxr167Rvn17HBwcKFWqFKNGjSI7O9vi+QpVAXHs6BGGvjOI0GaNCPb3Zc/un5WOZLB+7Wq6de5Ag7o1aVC3Jr1ee4Xfft2ndCyDmJgYPhr9Pk0b1qNerSC6de7A2TOnlY4FwOJFC3itR1dC6tSgWeMQhg99h3+uXFY6lkHb1i2oHuCba5o6eYLS0QyUen+L2RUholdtTn/Vmehlr7LzkxepWcEtz3W/6FeP5NW9eLuNX57LbYpY8+vU9iSv7kVgOZf8jJ3L2tWraNuqBXVqBBLWszunT50q0Nd/lHlzZuXa7zp1aKN0LED9x60pVhacnsaRI0dYsGABQUFBRvNHjBjBDz/8wIYNG9i3bx+3bt2iS5cuhuVarZb27duTlZXFH3/8wfLly1m2bBnjxo17yiSPVqiGMDIy0vH19aVTl66MHDZE6ThGSnl4MmzE+5QtVw69Xs8P321h2JDBrNu0mUqVKiuaLSU5mTd6vUqduvWYPX8Rri4uXL16FScnZ0VzPXD0yGFeeTUM/8BAtNlaZn31OYMG9Ofb73/EwcFB6XisWrsRnU5rePzXpUsMGtCXVq3V8Ytcyfd31oAQqr5QgoHzfic6MYMejXzY8lEo9UZ9T1RihmG9l2q/QO1K7txKSH/ktia+VpPopAyCHrlG/tixfRufzYhgzPgJBAYGs2rFct4e2J/vtu7AzS3vYqggVaxUmQVfLzU81mg0Cqb5l9qPW1OUvIwzNTWVsLAwFi1axOTJkw3zk5OTWbx4MatXr6ZFixYALF26lKpVq3Lw4EHq16/Pzp07OXfuHD///DMeHh5Ur16dSZMmMXr0aD755BNsbGwslrNQ9UA0atyUIcNG0DK0ldJRcmnWvAWNmzSlXLnylC/vw9BhI3BwcODUyRNKR2PpkkV4enoycXIEgYFBlC7zAg0aNuKFsmWVjgbAvIWL6di5C5UqVcbXz4+JU6YRFXWLyHNnlY4GgKurK+7uJQ3T/n17eeGFstSuU1fpaIBy769dUQ0v1y3LuNV/8sf5WC7H3GHaplNciblD/1Bfw3peLvbM6FOHAXN+455Wl+e2QoO9aRHozZhVx/I1c15WLF9Kl2496NS5KxUrVWLM+AnY2dmx5dtNBZ4lLxqNxmj/c3FxVToSoP7j1hRL9kBkZmaSkpJiNGVmZj7ytQcPHkz79u0JDQ01mn/s2DHu3btnNN/Pz4+yZcty4MABAA4cOEBgYCAeHh6GdV588UVSUlI4e9aybV+oCojnhVarZfu2H8nISCc4uIbScdi3dw/V/AN4f+S7NG8SwivdOrFp43qlYz1S6p07ADg5q6OH5GH37mWxbev3dOzcVTUnYSn1/hbRWFFEY03mPa3R/IwsLfV9SwL3r7Vf+E4jZv54jvM3k/PcTkknO2a+WZ+Bc38jI9Py47iPcy8ri8hzZ6kf0sAwz9ramvr1G3Dq5PECzfIo165dpVXzRrRv05Lw0e8RFXVL6Uh5UvNxm98iIiJwdnY2miIiIvJcd+3atfz55595Lo+OjsbGxoYSJUoYzffw8CA6OtqwzsPFw4PlD5ZZUqEawlC7Sxcv0Ou1nmRlZeLg4MAXM+dQsVIlpWNx48Z1Nqxbw+u9+/LmgEGcOXOaGRGTKVq0KC937Kx0PCM6nY4Z06dSvUZNKleuonScXPbs/pk7d+7wcif1tJtS72/q3WwOXYxlVOdALtxMJjb5Lt0alKduZXcuR9//YzKiQwDZWh3zd5x/5HbmDWrAkt2XOH4lgbLujvmWNy+JSYlotdpcQxVubm5cUcF4fmBQEBMnR1C+vA9xcbeZP3cO/XqHsXHLDzg6FlM6noHaj9u8WLL+Dw8PZ+TIkUbzbG1tc613/fp1hg0bxq5du7Czs7NcgHxiVgHx559/4uLigo+PDwArVqxg/vz5XLt2jXLlyjFkyBB69uxpcjuZmZm5um/0Gts8G7QwKV/eh/WbtpCaeoddO39i7EejWbxspeJFhE6np5p/AO8Ov7+D+1Wtxt+XLrFx/VrVFRBTJ0/g70uXWLZitdJR8rTl2000bNSEUqU8TK9cQJR8fwfO/Z3ZAxtwYW43srU6Tv6TwMY//qG6jxvVfVwZ1MaPJh/9+Ojnv+hHMfuifP7dmXzN+bxq1Lip4f9VfP0ICAymXevm7Nyxnc5duyuYzJjaj9u8WLIH0db2yf6+HTt2jNjYWGrWrGmYp9Vq2b9/P7Nnz+ann34iKyuLpKQko16ImJgYPD09AfD09OTw4cNG231wlcaDdSzFrCGMvn378vfffwPw9ddfM3DgQGrXrs3HH39MnTp1GDBgAEuWLDG5nby6cz6dnnd3TmFS1MaGsuXKUc0/gGEj3qOKrx+rVn6jdCxKlixJxYoVjeb5VKiguq7QqZMnsn/fLyxauhwPCx8IlnDr1k0OHfyDzl27KR3FiJLv75XYVNpP2olX3zVUG/otLcZup6jGmn9i7xDiW4qSTnacndWF+BVhxK8Io1zJYkx5vRanvrpf2DTx96RuZXduf/Ma8SvCOP5FJwB+mdyOeYMaPOaVLcOlhAsajYb4+Hij+fHx8bi7u+f765vLycmJsuXKc/3aNaWjGKj9uFWTli1bcvr0aU6cOGGYateuTVhYmOH/RYsWZffu3YbnXLhwgWvXrhESEgJASEgIp0+fJjY21rDOrl27cHJyolq1ahbNa1YPxKVLl6hc+f4VA3PnzuWrr75iwIABhuV16tRhypQp9OvX77Hbyas7R68p3L0PedHpdNzLylI6BsE1avLPP1eM5l29+g9eXqUVSmRMr9cTMWUSe3bvYvGyFZQp84LSkfL03eZvcXV1o3GTZkpHMaKG9zc9M5v0zGxKONrQIsib8Wv+5LvDV/nljPGY7LcftmTdb5dZue/+B5XRyw8zef2/Z417udizOTyUvjN/5ejfcfmeu6iNDVWr+XPo4AFatLx/4ppOp+PQoQP0fPX1fH99c6Wnp3Hj+nXcO5RUOspzc9w+ihInCBYvXpyAgACjeY6Ojri5uRnm9+/fn5EjR+Lq6oqTkxNDhw4lJCSE+vXrA9C6dWuqVatGr169mDFjBtHR0YwZM4bBgwdbvJffrALCwcGBuLg4ypUrx82bN6lb1/gs83r16nHlypVHPPtfeXXn3LXAuVHpaWlce6jyvnnjBucjI3F2dsbL2/vZX+AZfPXF/2jUuAmeXl6kp6Wx7cetHD1ymHkLFyuaC+D1Xn14o9erfL1wPq3btOXM6VNs2rieseMnKh0NgKmTJrB921a+nDUXRwdH4m7fBqBY8eKqGSfU6XR8v+VbOnTsRJEi6jq1SMn3t2WQF2DFX1EpVPAozsTXanLpVjIr9/1FtlZPYqpxAX1PqyMmKYO/olIAuBGfDvx7aWfa3XsAXIm989hLPi2pV5++jP1oNP7+AQQEBrFyxXIyMjLo1LmL6Sfns88/nU6TZs3x8vbmdmws8+bMQqOxpk27l5SO9lwct4+jlpOgc/riiy+wtrama9euZGZm8uKLLzJ37lzDco1Gw9atW3n77bcJCQnB0dGRPn36MHGi5Y93K71er3/SlXv16oWtrS1ff/01PXr0wNfXl0mTJhmWR0REsGbNGk49xZesWKKAOHL4EG/27Z1r/ssdOzNp6rRnf4FnMH7sRxw+eJDbt2MpVrw4Var40rf/AEIaNHzmbT/5O/ho+3/Zy8yvPufa1X8oXboMr/fpS9duPZ59wzz7yUjB/r55zp84OYKOz/hL3BJtB/DH77/xzv9/N0C58j6W2agF5df769lnxWOXd65XjvE9a+Dt6kBiaibfH7nGpHUnSMm4l+f6p77qzLztkcx7xEmVZd0dOT2zC43Ct3L6auJjXzvmm15P9kM8gTWrVrJ86WLi4m7j61eV0R+NISgo+Jm2aYl9b/T7I/jz2BGSkpJwcXWlRo1aDHl3hEUu0VXzcQtgl891+voTlhvi61Fd2Q+w+cWsAuLWrVs0bNiQsmXLUrt2bebNm0etWrWoWrUqFy5c4ODBg2zevJl27dqZHcQSBcR/laX+COYXlRbygPrbTu1MFRBKsmQBkR/Uvu+p+biF/C8gNliwgOheSAsIs4Z5vL29OX78OCEhIezYsQO9Xs/hw4fZuXMnZcqU4ffff3+q4kEIIYRQEysrK4tNhZXZNVyJEiWYNm0a06YpOyQghBBCCOWo62wvIYQQQgXka5pNkwJCCCGEyKEwDz1YihQQQgghRA5SPpgmvTRCCCGEMJv0QAghhBA5yAiGaVJACCGEEDlYyyCGSTKEIYQQQgizSQ+EEEIIkYMMYZgmBYQQQgiRg5UMYZgkQxhCCCGEMJv0QAghhBA5yBCGaVJAFAJq39HVfNdBtbed2qn5jpcuXRcoHeGxEjcNVDrCY+nUfOAC+f1VT3IVhmkyhCGEEEIIs0kPhBBCCJGD9E6aJgWEEEIIkYMUEKZJASGEEELkIJdxmibnQAghhBDCbNIDIYQQQuRgLR0QJkkBIYQQQuQgQximyRCGEEIIIcwmPRBCCCFEDnIVhmlSQAghhBA5yBCGaTKEIYQQQgizSQ+EEEIIkYNchWFaoeqBOHb0CEPfGURos0YE+/uyZ/fPSkfKZe3qVbRt1YI6NQIJ69md06dOKR0pl8WLFhLs78uMiClKRwFg3pxZVA/wNZo6dWijdKxHUlv7yXHxaMXsi/Jp/wZcWPQaCev7s3d6R2pVKmlYXsrZnoXvNuPy0teJX9+P78a3o6KXk9E2+rWuyk+TOxCzpi8Z3w3E2dGmQLIDrF+7mm6dO9Cgbk0a1K1Jr9de4bdf9xXY6z/s2NEjDBs8iFbNG1MjwI+9OfYzvV7P3NkzadWsMfVrBTPwzb5cvfqPIlmfhJUF/xVWhaqAyMhIx9fXl/Ax45WOkqcd27fx2YwIBr4zmLUbNuPr68fbA/sTHx+vdDSDM6dPsXHDWqpU8VU6ipGKlSrz8y+/Gaal36xWOlKe1Nh+clw82rwhTWlRvTT9vthL7Xc38PPxG/w4sT3erg4ArP/oRXw8neg+5Sfqj9jEtdg7bJv4Eg62/3beOtgWYdfx63y68Xi+582plIcnw0a8z5oN37J6/Sbq1qvPsCGD+euvSwWeJSMjgyq+foR/PC7P5cuWfM2aVSv4aNwnfLN6Pfb29gwe+CaZmZkFnFRYSqEqIBo1bsqQYSNoGdpK6Sh5WrF8KV269aBT565UrFSJMeMnYGdnx5ZvNykdDYD0tDTCR49i/ITJODk7Kx3HiEajwd29pGFycXFVOlIuam0/OS7yZmejoVOIDx8vO8Tv56K4HJ3ClLXH+DsqhQFt/ank7Uw9Pw/enfcrx/66zaWbybw7/1fsbIrQo0klw3Zm/3Cazzad4NCFmHzNm5dmzVvQuElTypUrT/nyPgwdNgIHBwdOnTxR4FkaNW7C4HeH0yKP/Uyv17N6xTcMeGsQzVu0pIqvL5OmTud2bGyungq1sLKy3FRYFaoCQs3uZWURee4s9UMaGOZZW1tTv34DTp0s+E8ueZk6eSJNmjQ1yqgW165dpVXzRrRv05Lw0e8RFXVL6Ui5qLn91ErJ46KIxpoiGmvu3tMazb+blU2Dqp7YFtXcf/zQcr0esrK1NKjqma/ZnoZWq2X7th/JyEgnOLiG0nGM3Lxxg7i429R76H0uXrw4AUFBihQ7T8LKglNhJSdRFpDEpES0Wi1ubm5G893c3Lhy5bJCqf61fduPREaeY/W6jUpHySUwKIiJkyMoX96HuLjbzJ87h369w9i45QccHYspHQ9Qd/upmZLHRWrGPQ6ejya8R00u3EgkJimDHo0rUc/Xg7+jU7hwI4lrsXeY1KsuQ+buJy0zm3dfDqSMezE8/3+IQw0uXbxAr9d6kpWViYODA1/MnEPFSpVMP7EAxcXdBsA11/vsTnxcnBKRTLIuzF0HFmJWATF06FB69OhB48aNn+lFMzMzc4176TW22NraPtN2xdOJjopixrQpLFi0RJXvQaPGTQ3/r+LrR0BgMO1aN2fnju107tpdwWT3qb39xKP1+2IvC4Y25fLSXmRrdZz4O471v/5NjYruZGt19Jy2k3lDmhK1ui/ZWh17Tt5kx9FrquqWLl/eh/WbtpCaeoddO39i7EejWbxspeqKCFH4mFVAzJkzh7lz51KxYkX69+9Pnz598PQ0vysvIiKCCRMmGM37eOx4xoz7xOxtPS9cSrig0WhynRgWHx+Pu7u7QqnuO3fuLAnx8fTs3sUwT6vVcuzoEdauWcWR46fRaDQKJjTm5ORE2XLluX7tmtJRgOev/dRE6ePiSnQKrT/+AQfbIjg52BCdmM6KUaFciUkB4PjfcdQfsQknBxtsilgTl3KX/Z924thf6vnUXNTGhrLlygFQzT+As2dOs2rlN4z7ZKLCyf7l7n7/ypaE+HhKlixlmB8fH4evb1WlYj2WimpE1TL7HIidO3fSrl07PvvsM8qWLUvHjh3ZunUrOp3uibcRHh5OcnKy0TRqdLi5UZ4rRW1sqFrNn0MHDxjm6XQ6Dh06QJDC45X16tdn45YfWLdpi2Hy9w+g3UsdWLdpi+r++KWnp3Hj+nXcS5Y0vXIBeN7aT03UclykZ2YTnZhOCUcbQquXYeuhq0bLU9KziEu5S0UvJ2pWLMnWQ/8UWDZz6XQ67mVlKR3DSOkyZXB3L2n0PqempnLm1CmCgqsrF+xx5CQIk8w+ByIwMJCWLVvy6aefsnnzZpYsWUKnTp3w8PDgjTfeoG/fvlQy0XVma5t7uOJutrlJcktPS+PaQ59Kb964wfnISJydnfHy9n72F3hGvfr0ZexHo/H3DyAgMIiVK5aTkZFBp85dTD85Hzk6FqNy5SpG8+wdHCjhXCLXfCV8/ul0mjRrjpe3N7djY5k3ZxYajTVt2r2kdDRA/e0nx8WjhdYogxVWXLyZREUvJ6a+UZ+LN5P4ZvcFALo0qMDtlAyu304loJwrn73ZkB8O/cPuEzcM2/AoYY+HiwMVve5feRNQzpU7Gfe4fjuVxNT8vUTxqy/+R6PGTfD08iI9LY1tP27l6JHDzFu4OF9fNy/p6WlGvYI3b97gwvlInJyd8fLy5rVevfl64XzKlitP6dKlmTt7JiVLlaJ5y9ACzyos46lPoixatCg9evSgR48eXLt2jSVLlrBs2TKmTZuGVqs1vYF8cPbsGd7s29vw+LMZEQC83LEzk6ZOUyTTw9q0bUdiQgJzZ88kLu42vn5Vmbvga9wUHsJQu5iYaMI/GElSUhIurq7UqFGLb1atx9VVfZdyqpEcF4/m7GDDxF51Ke1ejIQ7d/nuwBXGrzxCtvZ+j6qnqwPT+4dQytme6MR0Vu29SMT6P4228Wabaox5tbbh8c8RHQEY8NVeVu65mK/5ExLiGRM+mtu3YylWvDhVqvgyb+FiQho0zNfXzcu5M2cY0K+P4fH/Ztzftzp07MTEKdN4o9+bZGRkMPmTcdy5k0L1mrWYM3+Ras8bKsxfAGUpVnq9Xv+kK1tbWxMdHU2pUqXyXK7X6/n5559p1cr8680t0QMh1OnJ97CCp6aT4YRluXRdoHSEx0rcNFDpCI+lU/OBCzgUzd+D9/DlZIttq24F9XwvjCWZdQ5EuXLlHjuea2Vl9VTFgxBCCCGeL2YNYVy5ciW/cgghhBCqIZ2TpskXSQkhhBA5SQVhknyVtRBCCCHMJj0QQgghRA5yFYZpUkAIIYQQOcgVWqZJASGEEELkIPWDaXIOhBBCCCHMJj0QQgghRE7SBWGSFBBCCCFEDnISpWkyhCGEEEIIs0kPhBBCCJGDXIVhmhQQQgghRA5SP5gmBYTId1LJPz2V3xBR1e9twkZ13+3So/cKpSM8VvTyXkpHEConBYQQQgiRk4qLY7WQAkIIIYTIQa7CME2uwhBCCCGE2aSAEEIIIXKwsrLcZI6IiAjq1KlD8eLFKVWqFJ06deLChQtG69y9e5fBgwfj5uZGsWLF6Nq1KzExMUbrXLt2jfbt2+Pg4ECpUqUYNWoU2dnZz9osRqSAEEIIIXKwsuBkjn379jF48GAOHjzIrl27uHfvHq1btyYtLc2wzogRI/jhhx/YsGED+/bt49atW3Tp0sWwXKvV0r59e7Kysvjjjz9Yvnw5y5YtY9y4cU/VFo9ipder4zzvu5YtjIQoFNRxdD6amq/CUHvbefaRqzCehX3R/N3+mZupFttWQOliT/3c27dvU6pUKfbt20eTJk1ITk6mZMmSrF69mm7dugFw/vx5qlatyoEDB6hfvz7bt2/npZde4tatW3h4eAAwf/58Ro8eze3bt7GxsbHIzyU9EEIIIUQ+yszMJCUlxWjKzMx8oucmJycD4OrqCsCxY8e4d+8eoaGhhnX8/PwoW7YsBw4cAODAgQMEBgYaigeAF198kZSUFM6ePWupH0sKCCGEECInKwv+i4iIwNnZ2WiKiIgwmUGn0zF8+HAaNmxIQEAAANHR0djY2FCiRAmjdT08PIiOjjas83Dx8GD5g2WWIpdxCiGEEDlYcnguPDyckSNHGs2ztbU1+bzBgwdz5swZfvvtN8uFsSApIIQQQoh8ZGtr+0QFw8OGDBnC1q1b2b9/P2XKlDHM9/T0JCsri6SkJKNeiJiYGDw9PQ3rHD582Gh7D67SeLCOJcgQhhBCCJGDUldh6PV6hgwZwubNm9mzZw8+Pj5Gy2vVqkXRokXZvXu3Yd6FCxe4du0aISEhAISEhHD69GliY2MN6+zatQsnJyeqVatmZqJHkx4IIYQQIieFrjAaPHgwq1ev5rvvvqN48eKGcxacnZ2xt7fH2dmZ/v37M3LkSFxdXXFycmLo0KGEhIRQv359AFq3bk21atXo1asXM2bMIDo6mjFjxjB48GCze0Iep9D0QKxfu5punTvQoG5NGtStSa/XXuG3X/cpHeuRFi9aSLC/LzMipigdJRe1ZVP7e3vs6BGGvjOI0GaNCPb3Zc/un5WOZGTenFlUD/A1mjp1aKN0LCNrV6+ibasW1KkRSFjP7pw+dUrpSIDybVfMrggRvWpz+qvORC97lZ2fvEjNCm55rvtFv3okr+7F2238jOaf+qozyat7GU0jOvjne/a2rVvkarvqAb5MnTwh31/7eTZv3jySk5Np1qwZXl5ehmndunWGdb744gteeuklunbtSpMmTfD09OTbb781LNdoNGzduhWNRkNISAivv/46vXv3ZuLEiRbNWmh6IEp5eDJsxPuULVcOvV7PD99tYdiQwazbtJlKlSorHc/ImdOn2LhhLVWq+CodJRc1ZlP7e5uRkY6vry+dunRl5LAhSsfJU8VKlVnw9VLDY41Go2AaYzu2b+OzGRGMGT+BwMBgVq1YztsD+/Pd1h24ueX9x7IgKdl2swaEUPWFEgyc9zvRiRn0aOTDlo9CqTfqe6ISMwzrvVT7BWpXcudWQnqe25m84QTL91wyPE4tgC/eWbV2Izqd1vD4r0uXGDSgL61aq6t4fRSl7oXxJF/NZGdnx5w5c5gzZ84j1ylXrhzbtm2zZLRcCk0PRLPmLWjcpCnlypWnfHkfhg4bgYODA6dOnlA6mpH0tDTCR49i/ITJODk7Kx3HiFqzqf29bdS4KUOGjaBlaCulozySRqPB3b2kYXJxcVU6ksGK5Uvp0q0HnTp3pWKlSowZPwE7Ozu2fLtJ6WiAcm1nV1TDy3XLMm71n/xxPpbLMXeYtukUV2Lu0D/03wLfy8WeGX3qMGDOb9zT6vLcVmrGPWKT7xqm9Mz8LyBcXV2N2m3/vr288EJZatepm++vbQlKfZX186TQFBAP02q1bN/2IxkZ6QQH11A6jpGpkyfSpElT6oc0UDpKLmrO9oCa31s1u3btKq2aN6J9m5aEj36PqKhbSkcC4F5WFpHnzhrtc9bW1tSv34BTJ48rmOxfSrVdEY0VRTTWZN7TGs3PyNJS37ckcP+P08J3GjHzx3Ocv5n8yG2NeDmAKwt68OvU9rz7UjU01gX7V+3evSy2bf2ejp27YlWY/6L+xxSaIQyASxcv0Ou1nmRlZeLg4MAXM+dQsVIlpWMZbN/2I5GR51i9bqPSUXJRczZQ/3urZoFBQUycHEH58j7Exd1m/tw59OsdxsYtP+Do+PRfsWsJiUmJaLXaXEMVbm5uXLlyWaFU/1Ky7VLvZnPoYiyjOgdy4WYyscl36dagPHUru3M5+g4AIzoEkK3VMX/H+UduZ8FP5zl5JYHE1EzqVSnJ+J418Chhz8crj+Vr/oft2f0zd+7c4eVOnQvsNZ+VlDmmmV1AzJ49m8OHD9OuXTt69uzJihUriIiIQKfT0aVLFyZOnEiRIo/fbGZmZq6v8dRrzL9ONqfy5X1Yv2kLqal32LXzJ8Z+NJrFy1aq4g9NdFQUM6ZNYcGiJRY9C9YS1JztATW/t2rXqHFTw/+r+PoREBhMu9bN2bljO527dlcwmfop3XYD5/7O7IENuDC3G9laHSf/SWDjH/9Q3ceN6j6uDGrjR5OPfnzsNuZsizT8/+z1JLKydXzZvz4T1h4nKzvvIQ9L2/LtJho2akKpUh6mV1YLqSBMMquAmDx5MjNmzKB169aMGDGCq1ev8umnnzJixAisra354osvKFq0KBMmPP4s24iIiFzrfDx2PGPGfWL2D/CwojY2lC1XDoBq/gGcPXOaVSu/Ydwnlj3z9GmcO3eWhPh4enY3vmPasaNHWLtmFUeOn1bsxDY1Z3tAze/t88bJyYmy5cpz/do1paPgUsIFjUZDfHy80fz4+Hjc3d0VSvVoBd12V2JTaT9pJw62RShuX5SYpAyWDm3MP7F3CPEtRUknO87O+ve4LaKxZsrrtXi7bVWChm3Oc5tH/4qjaBFrypYsxl9RKfn+M9y6dZNDB//gf1/OyvfXsiSlTqJ8nphVQCxbtoxly5bRpUsXTp48Sa1atVi+fDlhYWHA/Rt6fPDBByYLiLy+1lOvsfwnX51Ox72sLItv92nUq1+fjVt+MJo3/uNwyleoQN/+AxT9A63mbI+ipvf2eZOensaN69dx71BS6SgUtbGhajV/Dh08QIuW928OpNPpOHToAD1ffV3hdLkp1XbpmdmkZ2ZTwtGGFkHejF/zJ98dvsovZ4zva/Dthy1Z99tlVu77+5HbCizvilanIy7lbn7HBuC7zd/i6upG4ybNCuT1RMExq4C4desWtWvXBiA4OBhra2uqV69uWF6zZk1u3TJ9glFeX+v5rFcVffXF/2jUuAmeXl6kp6Wx7cetHD1ymHkLFz/bhi3E0bEYlStXMZpn7+BACecSueYXNDVnA/W/t+lpaVx76BPpzRs3OB8ZibOzM17e3gomu+/zT6fTpFlzvLy9uR0by7w5s9BorGnT7iWlowHQq09fxn40Gn//AAICg1i5YjkZGRl06tzF9JPzmdJt1zLIC7Dir6gUKngUZ+JrNbl0K5mV+/4iW6snMdW4iL6n1RGTlGHoWahT2Z3aFd359VwMqXfvUadySSJer826366QlJb/BbhOp+P7Ld/SoWMnk0PbaiPneppm1jvq6enJuXPnKFu2LJcuXUKr1XLu3Dn8/e9/KcnZs2cpVapUvgQ1JSEhnjHho7l9O5ZixYtTpYov8xYuJqRBQ0XyCMtR+3t79uwZ3uzb2/D4sxn377L3csfOTJo6TalYBjEx0YR/MJKkpCRcXF2pUaMW36xab7g9sNLatG1HYkICc2fPJC7uNr5+VZm74GvcVDCEoXTbOdnbML5nDbxdHUhMzeT7I9eYtO4E2VrT3xUAkHVPR9eQ8nzYNRjbotZcjU1l7vZIZm87l8/J7zt44A+iom7RqXPXAnk9S5L6wTQr/ZN8a8X/Gzt2LAsWLKBjx47s3r2bV155hdWrVxMeHo6VlRVTpkyhW7dufP7552YHKYDvNRHiufPkR6cy1PwpTe1t59lnhdIRHit6eS+lIzyWfdH83f7fsRmmV3pCFUvZW2xbamJWD8SECROwt7fnwIEDDBgwgA8//JDg4GA++OAD0tPT6dChA5MmTcqvrEIIIUTBUHFxrBZm9UDkJ+mBECI3dRydjyY9EE9PeiCeTX73QFy+bbmTTCuUtLPYttSkUH4TpRBCCCHy1/N1WqwQQghRANTcu6YWUkAIIYQQOUj9YJoMYQghhBDCbNIDIYQQQuQkXRAmSQEhhBBC5CD3wjBNCgghhBAiBzmJ0jQ5B0IIIYQQZpMeCCGEECIH6YAwTQoIIYQQIgcZwjBNhjCEEEIIYTa5F4b4T9PpVLH7P5K1tXwMelrq+M32aGr/hFsybLnSER7rzro++br9G4lZFttWGRcbi21LTWQIQwghhMhB7QWeGsgQhhBCCCHMJj0QQgghRA7SAWGaFBBCCCFEDjKEYZoMYQghhBDCbNIDIYQQQuQg98IwTQoIIYQQIiepH0ySAkIIIYTIQeoH0+QcCCGEEEKYTXoghBBCiBzkKgzTpIAQQgghcpCTKE2TIQwhhBBCmK1QFRDHjh5h6DuDCG3WiGB/X/bs/lnpSLmsXb2Ktq1aUKdGIGE9u3P61CmlIxmoOdvDFi9aSLC/LzMipijy+seOHmHYkEG0atGYGoF+7M2xn437+ENqBPoZTYMHvalI1gfU/t6qOV9MTAwfjX6fpg3rUa9WEN06d+DsmdNKxzKiRPsVsyvCtD51ODu7K7Erwvh5YltqVnQzLJ//dkPurOtjNH0bHmpY3qiaR67lD6aHt6MYKwtOhVShKiAyMtLx9fUlfMx4paPkacf2bXw2I4KB7wxm7YbN+Pr68fbA/sTHxysdTdXZHnbm9Ck2blhLlSq+imXIyMigShU/wj8e98h1GjRszK69vxqmiOn/K8CExtT+3qo5X0pyMm/0epUiRYsye/4ivv3uR0a+PxonJ2eloxko1X6zBzagRaA3b835jfrvf8/uU7f4fkxrvFwcDOvsPH6Dim+tM0z9Zu43LDt04bbRsopvrWPZ7otcibnDn38r/95L/WBaoSogGjVuypBhI2gZ2krpKHlasXwpXbr1oFPnrlSsVIkx4ydgZ2fHlm83KR1N1dkeSE9LI3z0KMZPmIyTs3K/wBs1bsLgd4fTouWj9zMbGxvc3UsaJiXzqv29VXO+pUsW4enpycTJEQQGBlG6zAs0aNiIF8qWVTqagRLtZ1dUQ8d65Ri76ii/R8ZwOeYOERtPcjn6Dm+2/re4z8rWEZt81zAlpf17i+x7WuNlCamZtK/9Ait/+SvfcgvLKlQFhJrdy8oi8txZ6oc0MMyztramfv0GnDp5XMFk6s72sKmTJ9KkSVOjnGp19OhhWjRtQKcObZgy6ROSkhIVyaH291bt+fbt3UM1/wDeH/kuzZuE8Eq3TmzauF7pWAZKtV8RjRVFNNbcvac1mn83K5sQ31KGx42qeXJ5YQ/+/KITX/Svj2sx20dus12tF3AtbquaAsLKynJTYWX2VRhRUVHMmzeP3377jaioKKytralQoQKdOnXijTfeQKPR5EfO515iUiJarRY3N+OxPTc3N65cuaxQqvvUnO2B7dt+JDLyHKvXbVQ6ikkNGjWmRWhrSpcuzY3r15k18wuGvP0Wy1euLfDjQ+3vrdrz3bhxnQ3r1vB67768OWAQZ86cZkbEZIoWLcrLHTsrHU+x9ku9m82hC7GM7hLMhZvJxCbdpXtDH+pWKcnl6DsA7Dp5k+8PX+Of2DtU8CjO+Fdrsik8lJZjtqHT63Nts3eLyvx88ha3EtLzLbc55CoM08wqII4ePUpoaCiVKlXC3t6eS5cu8dprr5GVlcX777/PkiVL2LFjB8WLF3/sdjIzM8nMzDSap9fYYmv76OpU/HdFR0UxY9oUFixa8lzsI23atjf8v3IVXypX8aVDu1YcPXKYevVDFEwmzKXT6anmH8C7w0cC4Fe1Gn9fusTG9WtVUUAoacCc35g7qAGX5vcgW6vjxJUENvx+hRoV7hczm/74x7DuuetJnLmWyOlZXWns78G+M9FG2/J2dSA02JveX+wryB9BPCOzhjCGDx/OiBEjOHr0KL/++ivLli3j4sWLrF27lsuXL5Oens6YMWNMbiciIgJnZ2ej6dPpEU/9QzwPXEq4oNFocp3YFB8fj7u7u0Kp7lNzNoBz586SEB9Pz+5dqBlUjZpB1Th65DCrV62gZlA1tFqt6Y0oqMwLL1DCxYXr164W+Gur/b1Ve76SJUtSsWJFo3k+FSoQFXVLoUTGlGy/KzF3aDvhJzx6r8LvnY00//hHimqs+ScmNc/1/4lNJS7lLhU8nXIte71ZJRLuZLLt2PV8zWwOGcIwzawC4s8//6RXr16Gx6+99hp//vknMTExuLi4MGPGDDZuNN3FHB4eTnJystE0anS4+emfI0VtbKhazZ9DBw8Y5ul0Og4dOkBQcA0Fk6k7G0C9+vXZuOUH1m3aYpj8/QNo91IH1m3aovphs5joaJKTknAvWcr0yham9vdW7fmCa9Tkn3+uGM27evUfvLxKK5TImBraLz0zm5ikDEo42tAyuDQ/Hr2W53rerg64FrMlJjEj17LXm1Vizf7LZGtzD20I9TJrCKNUqVJERUVRoUIF4P710dnZ2Tg53a8oK1euTEJCgsnt2NrmHq64m21Okrylp6Vx7dq/O+/NGzc4HxmJs7MzXt7ez/4Cz6hXn76M/Wg0/v4BBAQGsXLFcjIyMujUuYvS0VSdzdGxGJUrVzGaZ+/gQAnnErnmF4T09DSuP7yf3bzBhfOROP1/b9qCeXNoGdoad3d3rl+/zleff8oLZcvSoGGjAs8K6n5vQd35Xu/Vhzd6vcrXC+fTuk1bzpw+xaaN6xk7fqLS0QyUar+Wwd5YAZdupVDBsziTX6/NpVvJrPjlLxxtixDeLZjvDl8lJikDH4/iTAqrzeXoFH4+edNoO00DPPHxKM7yPRfzNa+5CnPPgaWYVUB06tSJQYMG8emnn2Jra8ukSZNo2rQp9vb2AFy4cIHSpZWrzM+ePcObfXsbHn824/6wyMsdOzNp6jSlYhm0aduOxIQE5s6eSVzcbXz9qjJ3wde4qaCrVs3Z1Obc2TMM6NfH8Ph/n97ftzq83ImPxn7CpYsX+OH7LdxJuUPJUiUJCWnIO0OGYWNjo0hetb+3as4XEBjE51/OZuZXn7Nw/hxKly7DqNEf0f6ll5WOZqBU+znZF+WTV2tR2s2BxNRMvjt0jYlr/yRbq6eItR7/ci681rQizo42RCVksOfULSatP05Wts5oO72bV+bghVgu3krJ17zC8qz0+jxOh32E1NRU+vfvz7fffotWqyUkJISVK1fi4+MDwM6dO0lOTqZ79+5mB7FED4QQ5tLp1N1lam0tH4Oe1pP/ZlOG2j/hlgxbrnSEx7qzro/plZ5BcobO9EpPyNm+cH5jglkFxAN3794lOzubYsWKWSyIFBBCCVJAFF5SQDyb/3oBkXLXcgWEk13hLCCe6m6cdnZ2ls4hhBBCiOeI3M5bCCGEyEHlHUSqIAWEEEIIkZNUECYVzoEZIYQQQuQr6YEQQgghcpB7YZgmBYQQQgiRg9qvklEDGcIQQgghhNmkB0IIIYTIQTogTJMeCCGEECInKwtOZpozZw7ly5fHzs6OevXqcfjw4Wf9afKFFBBCCCFEDlYW/GeOdevWMXLkSMaPH8+ff/5JcHAwL774IrGxsfn0kz49KSCEEEIIlfj8888ZMGAAffv2pVq1asyfPx8HBweWLFmidLRc5BwIIYQQIgdLXoWRmZlJZmam0TxbW1tsbW2N5mVlZXHs2DHCw8MN86ytrQkNDeXAgQOWC2Qp+kLo7t27+vHjx+vv3r2rdJRc1JxNr5d8z0LN2fR6yfcs1JxNr5d8ajd+/Hg9YDSNHz8+13o3b97UA/o//vjDaP6oUaP0devWLaC0T+6p7sapdikpKTg7O5OcnIyTk5PScYyoORtIvmeh5mwg+Z6FmrOB5FO7J+2BuHXrFqVLl+aPP/4gJCTEMP+DDz5g3759HDp0qEDyPikZwhBCCCHyUV7FQl7c3d3RaDTExMQYzY+JicHT0zO/4j01OYlSCCGEUAEbGxtq1arF7t27DfN0Oh27d+826pFQC+mBEEIIIVRi5MiR9OnTh9q1a1O3bl2+/PJL0tLS6Nu3r9LRcimUBYStrS3jx49/oi6jgqbmbCD5noWas4HkexZqzgaSrzB55ZVXuH37NuPGjSM6Oprq1auzY8cOPDw8lI6WS6E8iVIIIYQQ+UvOgRBCCCGE2aSAEEIIIYTZpIAQQgghhNmkgBBCCCGE2QpdAaHW26Du37+fDh064O3tjZWVFVu2bFE6kpGIiAjq1KlD8eLFKVWqFJ06deLChQtKxwJg3rx5BAUF4eTkhJOTEyEhIWzfvl3pWI80bdo0rKysGD58uNJRAPjkk0+wsrIymvz8/JSOZXDz5k1ef/113NzcsLe3JzAwkKNHjyodC4Dy5cvnajsrKysGDx6sdDQAtFotY8eOxcfHB3t7eypWrMikSZNQy7nxd+7cYfjw4ZQrVw57e3saNGjAkSNHlI4lLKRQFRBqvg1qWloawcHBzJkzR+koedq3bx+DBw/m4MGD7Nq1i3v37tG6dWvS0tKUjkaZMmWYNm0ax44d4+jRo7Ro0YKOHTty9uxZpaPlcuTIERYsWEBQUJDSUYz4+/sTFRVlmH777TelIwGQmJhIw4YNKVq0KNu3b+fcuXP873//w8XFRelowP338+F227VrFwDdu3dXONl906dPZ968ecyePZvIyEimT5/OjBkzmDVrltLRAHjzzTfZtWsXK1as4PTp07Ru3ZrQ0FBu3rypdDRhCYreicPC6tatqx88eLDhsVar1Xt7e+sjIiIUTJUboN+8ebPSMR4rNjZWD+j37dundJQ8ubi46L/++mulYxi5c+eOvnLlyvpdu3bpmzZtqh82bJjSkfR6/f0b+QQHBysdI0+jR4/WN2rUSOkYT2zYsGH6ihUr6nU6ndJR9Hq9Xt++fXt9v379jOZ16dJFHxYWplCif6Wnp+s1Go1+69atRvNr1qyp//jjjxVKJSyp0PRAPLgNamhoqGGeqm+DqnLJyckAuLq6KpzEmFarZe3ataSlpanuq10HDx5M+/btjfZBtbh06RLe3t5UqFCBsLAwrl27pnQkAL7//ntq165N9+7dKVWqFDVq1GDRokVKx8pTVlYWK1eupF+/flhZ8l7Pz6BBgwbs3r2bixcvAnDy5El+++032rZtq3AyyM7ORqvVYmdnZzTf3t5eNT1g4tkUmm+ijIuLQ6vV5vq2Lg8PD86fP69QqueTTqdj+PDhNGzYkICAAKXjAHD69GlCQkK4e/cuxYoVY/PmzVSrVk3pWAZr167lzz//VOX4br169Vi2bBm+vr5ERUUxYcIEGjduzJkzZyhevLii2S5fvsy8efMYOXIkH330EUeOHOHdd9/FxsaGPn36KJotpy1btpCUlMQbb7yhdBSDDz/8kJSUFPz8/NBoNGi1WqZMmUJYWJjS0ShevDghISFMmjSJqlWr4uHhwZo1azhw4ACVKlVSOp6wgEJTQAjLGTx4MGfOnFHVpwRfX19OnDhBcnIyGzdupE+fPuzbt08VRcT169cZNmwYu3btyvVpSw0e/jQaFBREvXr1KFeuHOvXr6d///4KJrtfrNauXZupU6cCUKNGDc6cOcP8+fNVV0AsXryYtm3b4u3trXQUg/Xr17Nq1SpWr16Nv78/J06cYPjw4Xh7e6ui/VasWEG/fv0oXbo0Go2GmjVr8uqrr3Ls2DGlowkLKDQFxPN2G1S1GjJkCFu3bmX//v2UKVNG6TgGNjY2hk8ttWrV4siRI3z11VcsWLBA4WRw7NgxYmNjqVmzpmGeVqtl//79zJ49m8zMTDQajYIJjZUoUYIqVarw119/KR0FLy+vXEVg1apV2bRpk0KJ8nb16lV+/vlnvv32W6WjGBk1ahQffvghPXv2BCAwMJCrV68SERGhigKiYsWK7Nu3j7S0NFJSUvDy8uKVV16hQoUKSkcTFlBozoF43m6DqjZ6vZ4hQ4awefNm9uzZg4+Pj9KRHkun05GZmal0DABatmzJ6dOnOXHihGGqXbs2YWFhnDhxQlXFA0Bqaip///03Xl5eSkehYcOGuS4XvnjxIuXKlVMoUd6WLl1KqVKlaN++vdJRjKSnp2NtbfxrXKPRoNPpFEqUN0dHR7y8vEhMTOSnn36iY8eOSkcSFlBoeiBA3bdBTU1NNfrEd+XKFU6cOIGrqytly5ZVMNl9gwcPZvXq1Xz33XcUL16c6OhoAJydnbG3t1c0W3h4OG3btqVs2bLcuXOH1atX88svv/DTTz8pmuuB4sWL5zpXxNHRETc3N1WcQ/L+++/ToUMHypUrx61btxg/fjwajYZXX31V6WiMGDGCBg0aMHXqVHr06MHhw4dZuHAhCxcuVDqagU6nY+nSpfTp04ciRdT1K7NDhw5MmTKFsmXL4u/vz/Hjx/n888/p16+f0tEA+Omnn9Dr9fj6+vLXX38xatQo/Pz8VPE7WViA0peBWNqsWbP0ZcuW1dvY2Ojr1q2rP3jwoNKR9Hq9Xr937149kGvq06eP0tH0er0+z2yAfunSpUpH0/fr109frlw5vY2Njb5kyZL6li1b6nfu3Kl0rMdS02Wcr7zyit7Ly0tvY2OjL126tP6VV17R//XXX0rHMvjhhx/0AQEBeltbW72fn59+4cKFSkcy8tNPP+kB/YULF5SOkktKSop+2LBh+rJly+rt7Oz0FSpU0H/88cf6zMxMpaPp9Xq9ft26dfoKFSrobWxs9J6envrBgwfrk5KSlI4lLERu5y2EEEIIsxWacyCEEEIIUXCkgBBCCCGE2aSAEEIIIYTZpIAQQgghhNmkgBBCCCGE2aSAEEIIIYTZpIAQQgghhNmkgBBCCCGE2aSAEEIIIYTZpIAQQgghhNmkgBBCCCGE2aSAEEIIIYTZ/g+cjEWQbaJFLgAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns #导入包\n",
    "xtick=['0','1','2','3','4','5','6','7','8','9']\n",
    "ytick=['0','1','2','3','4','5','6','7','8','9']\n",
    "\n",
    "sns.heatmap(confusion_matrix,fmt='g', cmap='Blues',annot=True,cbar=True,xticklabels=xtick, yticklabels=ytick) #画热力图,annot=True 代表 在图上显示 对应的值， fmt 属性 代表输出值的格式，cbar=False, 不显示 热力棒\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 根据混沌矩阵可以知道以下值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "模型的准确率 97.36%\n",
      "模型的误分类率 2.64%\n"
     ]
    }
   ],
   "source": [
    "print(f'模型的准确率 {(np.sum(np.diagonal(confusion_matrix)) / 10000)*100:.2f}%')\n",
    "print(f'模型的误分类率 {(np.sum(confusion_matrix-np.diag(np.diagonal(confusion_matrix))) / 10000)*100:.2f}%')\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 真阳性率(TPR) 97.68%\n",
      "0 假阳性率(FPR) 0.25%\n",
      "0 真阴性率(TNR) 99.75%\n",
      "0 假阴性率(TPR) 1.12%\n",
      "0 precision 97.68%\n",
      "0 recall 98.88%\n",
      "0 F1 98.28%\n",
      "1 真阳性率(TPR) 98.94%\n",
      "1 假阳性率(FPR) 0.14%\n",
      "1 真阴性率(TNR) 99.86%\n",
      "1 假阴性率(TPR) 1.23%\n",
      "1 precision 98.94%\n",
      "1 recall 98.77%\n",
      "1 F1 98.85%\n",
      "2 真阳性率(TPR) 96.73%\n",
      "2 假阳性率(FPR) 0.38%\n",
      "2 真阴性率(TNR) 99.62%\n",
      "2 假阴性率(TPR) 2.42%\n",
      "2 precision 96.73%\n",
      "2 recall 97.58%\n",
      "2 F1 97.15%\n",
      "3 真阳性率(TPR) 96.30%\n",
      "3 假阳性率(FPR) 0.42%\n",
      "3 真阴性率(TNR) 99.58%\n",
      "3 假阴性率(TPR) 1.98%\n",
      "3 precision 96.30%\n",
      "3 recall 98.02%\n",
      "3 F1 97.15%\n",
      "4 真阳性率(TPR) 97.52%\n",
      "4 假阳性率(FPR) 0.27%\n",
      "4 真阴性率(TNR) 99.73%\n",
      "4 假阴性率(TPR) 3.77%\n",
      "4 precision 97.52%\n",
      "4 recall 96.23%\n",
      "4 F1 96.87%\n",
      "5 真阳性率(TPR) 98.30%\n",
      "5 假阳性率(FPR) 0.16%\n",
      "5 真阴性率(TNR) 99.84%\n",
      "5 假阴性率(TPR) 2.80%\n",
      "5 precision 98.30%\n",
      "5 recall 97.20%\n",
      "5 F1 97.75%\n",
      "6 真阳性率(TPR) 96.72%\n",
      "6 假阳性率(FPR) 0.35%\n",
      "6 真阴性率(TNR) 99.65%\n",
      "6 假阴性率(TPR) 1.46%\n",
      "6 precision 96.72%\n",
      "6 recall 98.54%\n",
      "6 F1 97.62%\n",
      "7 真阳性率(TPR) 97.25%\n",
      "7 假阳性率(FPR) 0.31%\n",
      "7 真阴性率(TNR) 99.69%\n",
      "7 假阴性率(TPR) 3.60%\n",
      "7 precision 97.25%\n",
      "7 recall 96.40%\n",
      "7 F1 96.82%\n",
      "8 真阳性率(TPR) 96.72%\n",
      "8 假阳性率(FPR) 0.35%\n",
      "8 真阴性率(TNR) 99.65%\n",
      "8 假阴性率(TPR) 2.98%\n",
      "8 precision 96.72%\n",
      "8 recall 97.02%\n",
      "8 F1 96.87%\n",
      "9 真阳性率(TPR) 97.36%\n",
      "9 假阳性率(FPR) 0.29%\n",
      "9 真阴性率(TNR) 99.71%\n",
      "9 假阴性率(TPR) 5.15%\n",
      "9 precision 97.36%\n",
      "9 recall 94.85%\n",
      "9 F1 96.08%\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    TP = confusion_matrix[i,i]\n",
    "    FP = np.sum(confusion_matrix,axis=1)[i]-TP\n",
    "    FN = np.sum(confusion_matrix,axis=0)[i]-TP\n",
    "    TN = np.sum(confusion_matrix)-TP-FP-FN\n",
    "    precision = TP / (TP+FP)\n",
    "    recall = TP / (TP+FN)\n",
    "    print(f'{i} 真阳性率(TPR) {( TP / (TP+FP))*100:.2f}%')\n",
    "    print(f'{i} 假阳性率(FPR) { (FP / (FP+TN))*100:.2f}%')\n",
    "    print(f'{i} 真阴性率(TNR) { (TN / (FP+TN))*100:.2f}%')\n",
    "    print(f'{i} 假阴性率(TPR) { (FN / (TP+FN))*100:.2f}%')\n",
    "    print(f'{i} precision { precision*100:.2f}%')\n",
    "    print(f'{i} recall { recall*100:.2f}%')\n",
    "    print(f'{i} F1 { ((2*precision*recall) / (precision+recall))*100:.2f}%')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
